DRF - How to change serializer.PrimaryKeyRelatedField's filter lookup key with condition?

Viewed 1442

I am trying to change serializers.PrimaryKeyRelatedField's filter lookup key based on other boolean field on serializer but I could not be successful. PrimaryKeyRelatedField filtering by pk key by default. In some condition (if condition field on serializer sent as True), I just want to change that filtering key with another field on related model's field like remote_id.

class SomeSerializer(serializers.Serializer):
    condition = serializers.BooleanField(default=False)
    model_pks = serializer.PrimaryKeyRelatedField(queryset=Model.objects.all(), many=True)

I tried to create new field which is inherited from PrimaryKeyRelatedField and override get_queryset method (not sure to override correct method) so far but I could not access condition and model_pks fields values.

class CustomPrimaryKeyRelatedField(PrimaryKeyRelatedField):
    def get_queryset(self):
        queryset = self.queryset
        # model_pks = sent model_pks
        if condition:
            return queryset.filter(remote_id__in=model_pks)
        return queryset.filter(id__in=model_pks)

Also, I tried to use SerializerMethodField instead of PrimaryKeyRelatedField like;

class SomeSerializer(serializers.Serializer):
    condition = serializers.BooleanField(default=False)
    model_pks = serializer.SerializerMethodField()

    def get_model_pks(self, value):
        pks = self.initial_data.get('model_pks', [])
        if value.get('condition', False):
            return Model.objects.filter(remote_id__in=pks)
        return Model.objects.filter(pk__in=pks)

It's provide changing lookup key based on condition but this time I could not access model_pks values with serializer.validated_data.

Is there any way to make conditional lookup key filtering using PrimaryKeyRelatedField?

1 Answers

I finally succeeded on my own question with creating custom primary key field. On this custom field I just recreated to_internal_value method and accessed condition value with self.root.

class CustomPrimaryKeyRelatedField(PrimaryKeyRelatedField):
    def to_internal_value(self, data):
        condition = self.root.initial_data.get('condition', False)

        if self.pk_field is not None:
            data = self.pk_field.to_internal_value(data)
        try:
            if condition:
                return self.get_queryset().get(remote_id=data)
            else:
                return self.get_queryset().get(pk=data)
        except ObjectDoesNotExist:
            self.fail('does_not_exist', pk_value=data)
        except (TypeError, ValueError):
            self.fail('incorrect_type', data_type=type(data).__name__)

I am not sure that this is the best way to deal with kind of this issues. But it solves my problem for now.

Related