Django REST 框架,如何在 ModelSerializer 中包含“__ all__”字段和相关字段?

我有两个模型,一个与 M2M 的关系和一个相关的名称。我想在序列化程序和相关字段中包含 所有字段。

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)

Py:

class ToppingSerializer(serializers.ModelSerializer):
class Meta:
model = Topping
fields = '__all__'

这是可行的,但是不包括相关的字段。

 fields = ['name', 'price', 'pizzas']

这正如我所希望的那样工作,但是当 Toppings 模型有很多字段时会发生什么呢。我想这样做:

fields = ['__all__', 'pizzas']

这种语法导致一个错误:

字段名 __all__对模型无效

有没有办法达到想要的行为?或者在使用相关名称时必须手动键入字段?

59367 次浏览

我刚查了姜戈休息框架的源代码。 框架中似乎不支持您想要的行为。

fields选项必须是列表、元组或文本 __all__

下面是相关源代码的一个片段:

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

不能将“ 所有”添加到元组或带字段的列表中..。

正如@DanEEStart 所说,DjangoRestFramework 没有一种简单的方法来扩展字段的“ 所有”值,因为 get_field_names方法似乎是被设计成 那样工作的。

但幸运的是,您可以重写这个方法,以便使用一种简单的方法来包含所有字段和关系,而无需枚举大量字段。

我重写这个方法如下:

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

按照下面的示例,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__'

注意: < em > 使用 Django Rest Framework 3.6.2版创建,可能会更改。如果将来有任何更改打破了上面发布的任何示例,请添加评论。

要包含序列化程序中定义的所有字段和其他字段,只需说 exclude = ()即可

class ToppingSerializer(serializers.HyperlinkedModelSerializer):
pizzas = '<>' #the extra attribute value
class Meta:
model = Topping
exclude = ()

这将列出带有额外参数 pizza 的所有字段值

嗨,我可以通过使用 Django 的 _ meta API来实现预期的结果,这似乎是从 Django 1.11开始就可用的。因此,在我的序列化程序中,我这样做了:

model = MyModel
fields = [field.name for field in model._meta.fields]
fields.append('any_other_field')

在编程中,总是有很多方法可以达到相同的结果,但是上面这个方法,对我来说真的很有效。

干杯!

我就是这么做的,简单多了

class OperativeForm(forms.ModelForm):
class Meta:
model = Operative
fields = '__all__'
exclude = ('name','objective',)
widgets = {'__all__':'required'}

如果您只是试图向序列化对象中添加额外的信息,则根本不需要更改字段部分。添加要添加的字段:

class MySerializer(serializers.ModelSerializer):
...
new_field = serializers.SerializerMethodField('new_field_method')


def new_field_method(self, modelPointer_):
return "MY VALUE"

那你还可以用

class Meta:
fields = '__all__'

建立在@Wand 精彩回答的基础上:

def build_fields(mdl,extra=[],exclude=[]):
fields = [field.name for field in mdl._meta.fields if field.name not in exclude]
fields += extra
return fields

用法:

model = User
fields = build_fields(model, ['snippets'], ['password'])

将返回 User 模型中的所有字段,其中包含相关的字段段,但不包含密码字段。