Django Rest框架,如何包含&_ 39; __ all __'字段和ModelSerializer中的相关字段?

时间:2016-07-07 12:24:49

标签: django django-models django-rest-framework

我有两个模型,一个具有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__对模型

无效

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

7 个答案:

答案 0 :(得分:23)

就像@DanEEStart所说,DjangoRestFramework没有一种简单的方法可以扩展所有' 所有'字段的值,因为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']

答案 1 :(得分:16)

我刚检查了Django Rest Framework的源代码。 框架中似乎不支持您想要的行为。

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

您无法在字段或列表中添加“所有”...

答案 2 :(得分:11)

一个老问题,但认为这可能在将来帮助其他人。

我刚刚遇到了类似的问题并得到了" 所有"通过按以下示例手动指定其他字段来工作选项。我不确定这是否也可以解决您的问题。它比我见过的任何东西都更清洁。

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

我正在使用Django Rest Framework版本3.6.2

请求的反向关系示例:

class TrackSerializer(serializers.ModelSerializer):
    album = AlbumSerializer(source='album_id')

    class Meta:
        model = Track
        fields = '__all__'

答案 3 :(得分:2)

您好我可以使用Django's _meta API来实现预期的结果,这似乎是自Django 1.11以来可用的。所以在我的序列化器中我做了:

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

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

干杯!

答案 4 :(得分:1)

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

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

这将使用额外参数pizzas列出所有字段值

答案 5 :(得分:0)

这就是我做到的方式,更容易

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

答案 6 :(得分:0)

如果您基本上只是想在序列化对象中添加额外的信息,则根本不需要更改字段部分。要添加字段,请执行以下操作:

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

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

那么您仍然可以使用

class Meta:
   fields = '__all__'