首页 > 解决方案 > Django Serializer - 决定在运行时序列化哪些字段

问题描述

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

这是我想做的一个例子:

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

然后我可以使用这个输出来填充 HTML 选择元素的选项。

同时FooSerializer看起来像这样:类

FooSerializer(serializers.ModelSerializer):

  id = serializers.ReadOnlyField()


  class Meta:
    model = ProgressNoteCustomType

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

    read_only_fields = ['id']

虽然我可以编写另一个序列化程序,它在定义中只有idandtitle字段Meta,但它不是DRY.

然后我有另一个场景,我想显示一个列表视图,用户可以在其中单击一个项目并对其进行编辑 - 这里我只想显示titlemodifiedactive。写类似的东西FooSerializer(queryset, many=True, fields=["id", "title", "active"])似乎是合适的解决方案,但无效。

我真的想避免为这 3 种不同的场景使用 3 种不同的序列化(其中常规FooSerializer(instance)是返回序列化程序中定义的所有字段的编辑/查看默认值)

标签: djangodjango-rest-frameworkdjango-serializer

解决方案


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' ])

医生在这里


推荐阅读