Сериализация связанных сводных моделей с Django Rest Framework - PullRequest
0 голосов
/ 27 февраля 2020

Я учусь Django и использую Django Rest Framework. В моем приложении у меня есть три разные модели

  • Бар (содержит информацию о баре, имеет несколько сортов пива через модель BarBeer)
  • Пиво (содержит информацию о пиве)
  • BarBeer (соединение между баром и пивом, имеет сводные поля, такие как алкоголь, тип, цена и объем)

Вот как определяются различные модели:

class Bar(models.Model):
    name = models.CharField(max_length=60)
    location = models.PointField()
    address = models.CharField(max_length=60)
    description = models.TextField(default='')

    beers = models.ManyToManyField('api.Beer', through='api.BarBeer')

class Beer(models.Model):
    name = models.CharField(max_length=60)
    alcohol = models.FloatField(default=0)

class BarBeer(models.Model):
    bar = models.ForeignKey(Bar, on_delete=models.CASCADE)
    beer = models.ForeignKey(Beer, on_delete=models.CASCADE)

    price = models.FloatField(default=0)
    type = EnumField(Type, default=Type.Cask)
    volume = models.IntegerField(default=0)

Теперь я хочу сериализовать данный бар со всеми сортами пива для этого конкретного бара , включая дополнительные поля в сводной модели BarBeer. Например, ниже я хотел бы получить выходные данные (обратите внимание на три дополнительных поля на пиве, которые получены из модели BarBeer):

{
    "id": 1,
    "name": "A bar",
    "beers": [
        {
            "id": 1,
            "name": "Ship Full of IPA",
            "alcohol": 6.5,
            "type": "bottle",
            "price": "35",
            "volume": "33"
        }
    ]
}

Я не могу понять, как получить дополнительные поля из сводной модели как часть сериализованного вывода. Вот как сейчас выглядит мой сериализатор:

class BarDetailsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bar
        fields = ('id', 'name', 'beers')
        depth = 3

Ответы [ 2 ]

0 голосов
/ 28 февраля 2020

Во-первых beers = models.ManyToManyField('api.Beer', through='api.BarBeer') это поле не обязательно, потому что вы уже создали таблицу с именем BarBeer. ManyToManyField означает добавление таблицы exra. Итак, если мы предположим, что это поле не существует, и у вас есть BarBeer table, вы можете сделать это с помощью BarBeerSerializer, например:

serializers.py

class BarBeerSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()
    alchol = serializers.SerializerMethodField()

    class Meta:
        model = BarBeer
        fields = ['id','name','alchol','type','price','volume']

    def get_name(self,obj):
        return obj.beer.name

    def get_alchol(self,obj):
       return obj.beer.alchol


class BarSerializer(serializers.ModelSerializer):
    beers = serializers.SerializerMethodField()
    class Meta:
        model = Bar
        fields = ['id', 'name', 'beers']

    def get_beers(self,obj:Bar):
        beers = obj.barbeer_set.all()
        return BarBeerSerializer(beers,many=True).data

Если есть ошибка, пожалуйста, спросите об этом в комментарии.

0 голосов
/ 27 февраля 2020

Один из способов сделать это - создать собственный сериализатор для модели BarBeer и передать в него два других сериализатора моделей, например: ~

class BarDetailsSerializer(serializers.Serializer):
    bar = BarSerializer()
    beer = BeerSerializer()
    price = serializers.FloatField(required=True)
    type = serializers.CharField(required=True)
    volume = serializers.IntegerField(required=True)

, просто передать объект BarBeer этому сериализатору и он будет возвращать все точки данных, даже для объектов, подключенных через внешний ключ.

Еще один способ добиться этого, поскольку точно такой же ответ, который вы упомянули в этом вопросе, состоял бы в создании средства визуализации для вашего API и формата и структурируйте данные так, как вы хотите, соответственно.

...