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')
в программировании всегда есть много способов, чтобы достичь того же результата, но это, действительно работал для меня.
Ура!