Django Rest 框架,如何在 ModelSerializer 中包含“__all__”字段和相关字段?
Posted
技术标签:
【中文标题】Django Rest 框架,如何在 ModelSerializer 中包含“__all__”字段和相关字段?【英文标题】:Django Rest framework, how to include '__all__' fields and a related field in ModelSerializer ? 【发布时间】:2016-11-09 18:26:59 【问题描述】:我有两个模型,一个具有 M2M 关系和一个相关名称。我想在序列化程序和相关字段中包含 所有 字段。
models.py:
class Pizza(models.Model):
name = models.CharField(max_length=50, unique=True)
toppings = models.ManyToManyField(Topping, null=True, blank=True, related_name='pizzas')
class Topping(models.Model):
name = models.CharField(max_length=50, unique=True)
price = models.IntegerField(default=0)
serializer.py:
class ToppingSerializer(serializers.ModelSerializer):
class Meta:
model = Topping
fields = '__all__'
这可行,但不包括相关字段。
fields = ['name', 'price', 'pizzas']
这完全符合我的要求,但是当 Toppings 模型有很多字段时会发生什么。我想做类似的事情:
fields = ['__all__', 'pizzas']
此语法导致错误提示:
字段名称
__all__
对模型无效
有没有办法实现想要的行为?或者使用相关名称时必须手动输入字段?
【问题讨论】:
***.com/questions/14573102/… - 答案再好不过了 - 如果来自作者本人的话。 @karthikr 这并没有真正解释如何做我想做的事。它只是解释了如何嵌套 M2M。我不想那样做。我想在序列化程序“字段”中包含相关字段和 all 标记 【参考方案1】:就像@DanEEStart 所说,DjangoRestFramework 没有简单的方法来扩展字段的“all”值,因为get_field_names
方法似乎设计为to work that way。
但幸运的是,您可以重写此方法,从而以一种简单的方式包含所有字段和关系,而无需枚举大量字段。
我这样重写这个方法:
class ToppingSerializer(serializers.ModelSerializer):
class Meta:
model = Topping
fields = '__all__'
extra_fields = ['pizzas']
def get_field_names(self, declared_fields, info):
expanded_fields = super(ToppingSerializer, self).get_field_names(declared_fields, info)
if getattr(self.Meta, 'extra_fields', None):
return expanded_fields + self.Meta.extra_fields
else:
return expanded_fields
注意这个方法只改变这个序列化器的行为,extra_fields
属性只对这个序列化器类起作用。
如果您有大量这样的序列化程序,您可以创建一个中间类,将这个get_fields_names
方法包含在一个地方并多次重复使用它们。有些是这样的:
class CustomSerializer(serializers.HyperlinkedModelSerializer):
def get_field_names(self, declared_fields, info):
expanded_fields = super(CustomSerializer, self).get_field_names(declared_fields, info)
if getattr(self.Meta, 'extra_fields', None):
return expanded_fields + self.Meta.extra_fields
else:
return expanded_fields
class ToppingSerializer(CustomSerializer):
class Meta:
model = Topping
fields = '__all__'
extra_fields = ['pizzas']
class AnotherSerializer(CustomSerializer):
class Meta:
model = Post
fields = '__all__'
extra_fields = ['comments']
【讨论】:
我只是想让你知道你是一个救星,非常感谢你的这个 sn-p。【参考方案2】:我刚刚查看了 Django Rest Framework 的源代码。 框架似乎不支持您想要的行为。
fields
选项必须是列表、元组或文本 __all__
。
这里是相关源码的sn-p:
ALL_FIELDS = '__all__'
if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)):
raise TypeError(
'The `fields` option must be a list or tuple or "__all__". '
'Got %s.' % type(fields).__name__
)
您不能将“all”另外添加到带有字段的元组或列表中...
【讨论】:
伙计,这是一个非常基本的功能,每次我查看 django 时,似乎一切都被打破或一成不变,无法制造智能工厂或任何东西,只需编写大量无用的代码对于您想做的任何简单的事情。谢谢你的回答【参考方案3】:fields="__all__"
选项可以通过按照以下示例手动指定附加字段来工作。对于这个问题,这是迄今为止最干净的解决方案。
嵌套关系
http://www.django-rest-framework.org/api-guide/relations/#nested-relationships
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = '__all__'
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = '__all__'
我认为这适用于同一页面上列出的任何其他相关字段选项:http://www.django-rest-framework.org/api-guide/relations/#serializer-relations
反向关系示例
class TrackSerializer(serializers.ModelSerializer):
album = AlbumSerializer(source='album_id')
class Meta:
model = Track
fields = '__all__'
注意: 使用 Django Rest Framework 3.6.2 版创建,可能会发生变化。如果未来的任何更改破坏了上面发布的任何示例,请添加评论。
【讨论】:
这在反向关系的情况下不起作用 -> django-rest-framework.org/api-guide/relations/… @IshanKhare 更新以表明这也适用于反向关系。 这确实应该被接受为正确答案,因为它解决了框架提供的功能范围内的问题,而无需额外的黑客攻击。【参考方案4】:嗨,我可以通过使用 Django's _meta API 来达到预期的结果,这似乎是从 Django 1.11 开始可用的。所以在我的序列化器中我做了:
model = MyModel
fields = [field.name for field in model._meta.fields]
fields.append('any_other_field')
在编程中,总是有很多方法可以达到相同的结果,但上面的这个对我真的很有效。
干杯!
【讨论】:
这在我看来效果最好。你也可以fields.extend(['field1', 'field2'])
这个好干净!【参考方案5】:
如果您尝试基本上只是将额外的信息添加到序列化对象中,则根本不需要更改字段部分。添加一个字段:
class MySerializer(serializers.ModelSerializer):
...
new_field = serializers.SerializerMethodField('new_field_method')
def new_field_method(self, modelPointer_):
return "MY VALUE"
那么你仍然可以使用
class Meta:
fields = '__all__'
【讨论】:
这应该是公认的答案。谢谢! 这是一个只读字段!【参考方案6】:要包含序列化程序中定义的所有字段和其他字段,您只需说exclude = ()
class ToppingSerializer(serializers.HyperlinkedModelSerializer):
pizzas = '<>' #the extra attribute value
class Meta:
model = Topping
exclude = ()
这将列出所有带有额外参数比萨饼的字段值
【讨论】:
【参考方案7】:这就是我的做法,更容易
class OperativeForm(forms.ModelForm):
class Meta:
model = Operative
fields = '__all__'
exclude = ('name','objective',)
widgets = '__all__':'required'
【讨论】:
收到此错误:Cannot set both 'fields' and 'exclude' options on serializer
以上是关于Django Rest 框架,如何在 ModelSerializer 中包含“__all__”字段和相关字段?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 django rest 框架中列出来自特定模型的所有对象?
如何获取主键相关字段嵌套序列化器django rest框架的所有值