DRF - 如何使用条件更改 serializer.PrimaryKeyRelatedField 的过滤器查找键?

Posted

技术标签:

【中文标题】DRF - 如何使用条件更改 serializer.PrimaryKeyRelatedField 的过滤器查找键?【英文标题】:DRF - How to change serializer.PrimaryKeyRelatedField's filter lookup key with condition? 【发布时间】:2020-02-18 15:47:11 【问题描述】:

我正在尝试根据序列化程序上的其他布尔字段更改serializers.PrimaryKeyRelatedField 的过滤器查找键,但我无法成功。 PrimaryKeyRelatedField 默认按pk 键过滤。在某些情况下(如果序列化程序上的condition 字段以True 发送),我只想将过滤键更改为相关模型字段上的另一个字段,例如remote_id

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

到目前为止,我尝试创建从 PrimaryKeyRelatedField 继承的新字段并覆盖 get_queryset 方法(不确定是否覆盖正确的方法),但我无法访问 conditionmodel_pks 字段值。

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)

另外,我尝试使用SerializerMethodField 而不是PrimaryKeyRelatedField 之类的;

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)

它提供了基于condition 的更改查找键,但这次我无法使用serializer.validated_data 访问model_pks 值。

有没有办法使用PrimaryKeyRelatedField 进行条件查找键过滤?

【问题讨论】:

【参考方案1】:

我终于通过创建自定义主键字段成功解决了我自己的问题。在这个自定义字段上,我刚刚重新创建了to_internal_value 方法并使用self.root 访问了condition 值。

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__)

我不确定这是处理此类问题的最佳方式。但它现在解决了我的问题。

【讨论】:

但是,这仅适用于发布请求权,因为我正在尝试过滤主键相关字段并在可浏览的 API 页面中仅显示它的相关对象,并且面临一些问题。为什么你还没有实现to_representation @ManishShah 是的。此序列化程序仅用于发布请求,因此我们不对 to_representation 方法执行任何操作。

以上是关于DRF - 如何使用条件更改 serializer.PrimaryKeyRelatedField 的过滤器查找键?的主要内容,如果未能解决你的问题,请参考以下文章

第三章drf框架 - 序列化组件 | Serializer

drf Serializer使用

DRF框架之Serializer序列化器的序列化操作

DRF框架之 serializers 序列化组件

DRF的Serializer和ModelSerializer

如何在 DRF 中序列化自定义用户模型