Django Rest framework, как включить " все " поля и связанное поле в ModelSerializer?

у меня есть две модели, одна с отношением 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'] 

это работает именно так, как я хочу, но что происходит, когда модель начинки имеет много полей. Я хочу сделать что-то вроде :

fields = ['__all__', 'pizzas']

этот синтаксис приводит к ошибке:

поле "Имя"__all__ недопустимо для модели

есть ли способ достичь желаемого поведения? Или поля должны быть введены вручную при использовании связанного имени ?

5 ответов


Я только что проверил исходный код 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__
        )

вы не можете добавить 'все' дополнительно к кортежу или списку с полями...


как сказал @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']

старый вопрос, но думал, что это может помочь другим в будущем.

у меня нет подобной проблемы и у "все" опция работает, указав дополнительное поле вручную в следующем примере. Я не уверен, что это также решит вашу проблему. Он намного чище, чем все остальное, что я видел.

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

чтобы включить все поля и другие поля, определенные в сериализаторе, вы можете просто сказать exclude = ()

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

Это список всех значений поля с дополнительной пиццы аргумент


Привет я мог бы достичь ожидаемого результата с помощью Джанго _meta по API, который, похоже, доступен с Django 1.11. Поэтому в моем сериализаторе я сделал:

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

в программировании всегда есть много способов, чтобы достичь того же результата, но это, действительно работал для меня.

Ура!