Django Serializer-确定在运行时对哪些字段进行序列化

时间:2018-08-18 02:52:46

标签: django django-rest-framework django-serializer

我正在使用DRF并具有序列化的模型。有时候我想将所有字段都包含在发送到api端点的数据中,有时候我只想属性的子集(例如列表视图vs编辑视图)。是否可以在一个序列化器中声明所有字段,然后在调用序列化器时仅指定一个子集。

这是我想做的事的一个例子:

queryset = Foo.objects.filter(active=True)
FooSerializer(queryset, many=True, fields=["id", "title"])

然后我可以使用此输出来填充HTML select元素的选项。

同时FooSerializer如下所示:

FooSerializer(serializers.ModelSerializer):

  id = serializers.ReadOnlyField()


  class Meta:
    model = ProgressNoteCustomType

    fields = ( 'id', 'title', 'modified', 'active', 'user' )

    read_only_fields = ['id']

虽然我可以编写另一个串行器,但在id定义中只有titleMeta字段,却不是DRY

然后,在另一种情况下,我想显示一个列表视图,用户可以单击该列表视图并对其进行编辑-在这里,我只想显示titlemodified和{{1 }}。编写类似active的内容似乎是适当的解决方案,但无效。

我真的想避免在这3种不同的情况下使用3种不同的序列化(常规FooSerializer(queryset, many=True, fields=["id", "title", "active"])是返回序列化程序中定义的所有字段的默认编辑/视图)

2 个答案:

答案 0 :(得分:1)

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)
        exclude = kwargs.pop('exclude', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)

        if exclude is not None:
            not_allowed = set(exclude)
            for exclude_name in not_allowed:
                self.fields.pop(exclude_name)

这就是您所需要的,用法如下:

FooSerializer(DynamicFieldsModelSerializer):
    ....

在views.py中:

FooSerializer(queryset, many=True, fields=["id", "title"])

FooSerializer(queryset, many=True, exclude=['modified', 'active', 'user' ])

Doc是here

答案 1 :(得分:1)

我改编自@Ykh的逻辑,

将您的 FooSerializer 更改为

class FooSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        fields = kwargs.pop('fields', None)
        exclude = kwargs.pop('exclude', None)
        if fields is not None and exclude is not None:
            serializers.ValidationError("fields and exclude are simultaneously not allowed")
        super().__init__(*args, **kwargs)
        if exclude:
            for item in set(exclude):
                self.fields.pop(item, None)
        if fields:
            for item in set(self.fields.keys()) - set(fields):
                self.fields.pop(item, None)

    class Meta:
        fields = '__all__'
        model = FooModel


用法

FooSerializer(queryset, many=True, exclude=['id'])

FooSerializer(queryset, many=True, fields=['id'])