我正在使用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
定义中只有title
和Meta
字段,却不是DRY
。
然后,在另一种情况下,我想显示一个列表视图,用户可以单击该列表视图并对其进行编辑-在这里,我只想显示title
,modified
和{{1 }}。编写类似active
的内容似乎是适当的解决方案,但无效。
我真的想避免在这3种不同的情况下使用3种不同的序列化(常规FooSerializer(queryset, many=True, fields=["id", "title", "active"])
是返回序列化程序中定义的所有字段的默认编辑/视图)
答案 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'])