Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 946
uedemir Avatar asked Oct 16 '22 10:10

uedemir


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.

like image 58
uedemir Avatar answered Oct 30 '22 21:10

uedemir