Отправка набора запросов Django с аннотацией к моему API для отдыха - PullRequest
1 голос
/ 29 апреля 2019

У меня есть две простые модели со случайными данными о телефонах.

class Phone(models.Model):
    name = models.CharField(max_length=200)
    description = models.CharField(max_length=400)
    image = models.ImageField(upload_to='phone_img/', max_length=255, null=True, blank=True )
    slug_phone = models.SlugField(blank=True)

class Price(models.Model):
    price = models.DecimalField(max_digits=6, decimal_places=2)
    date = models.DateField(null=True, blank=True) 
    phone = models.ForeignKey(Phone, on_delete=models.CASCADE)
    market = models.ForeignKey(Market, on_delete=models.CASCADE)

Я могу отправить простые данные через данные REST_framwork в мой API.

views.py

class SnippetList(generics.ListCreateAPIView):
    queryset = Price.objects.all()
    serializer_class = PriceSerializer

serializers.py

class PriceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Price
        fields = ('id', 'phone', 'price', 'date', 'market', )


    phone = serializers.StringRelatedField()
    market = serializers.StringRelatedField()

Теперь я хотел использовать метод annotate () с функцией Min () в QuerySet. Я хотел отобразить минимальную цену каждого телефона. Итак, я попробовал что-то вроде этого:

views.py

from django.db.models import Min

<....>

class SnippetList(generics.ListCreateAPIView):
    queryset = Price.objects.all()
    serializer_class = PriceSerializer
    def get_queryset(self):
        min_price = Phone.objects.annotate(Min('price__price'))

        return min_price

Конечно, это не сработало. я проследовал за сообщениями об ошибках сервера и закончился этим:

serializers.py

from rest_framework import serializers
from market.models import Price, Phone


class PriceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Price
        fields = ('id', 'phone', 'price', 'date', 'market')

    class Meta:
        model = Phone
        fields = ('name', 'phone', 'market', )


    phone = serializers.StringRelatedField()
    market = serializers.StringRelatedField()

Мой API показывает мне этот вывод, это не значение min_price, а по крайней мере что-то:

{ "счетчик": 7, "ряд": NULL, "предыдущие": NULL, "Результаты": [{ "Имя": "SAMSUNG Galaxy S10 "}, {" name ":" SAMSUNG Galaxy S10 plus "}, {" name ":" SAMSUNG Galaxy S10e "}, {" name ":" SAMSUNG Galaxy S8 "}, {" name ":" SAMSUNG Galaxy S8 Плюс "}, {" name ":" SAMSUNG Galaxy S9 "}, {" name ":" SAMSUNG Galaxy S9 плюс "}]}

Поэтому я спросил себя, куда поместить .annotate (Мин. ? Или я должен создать один ListCreateAPIView с queryset = Phone.objects.all ()? Можно ли отобразить данные min_price без нового поля в моем serializers.py?

1 Ответ

2 голосов
/ 29 апреля 2019

Я уже упоминал некоторые моменты в комментариях. Но я повторю это здесь: (

1. Если вы попытаетесь найти минимальное значение из модели Price, оно не даст ожидаемого результата. Поскольку каждая строка имеет только один атрибут price, следовательно, Min(price) становится price.

2. Если вы хотите сериализовать набор запросов определенной модели (скажем, Price), вы должны были использовать ModelSerializer, определенный с помощью model=Price в метаклассе сериализатора.

3. Вы не можете использовать два класса Meta в одном сериализаторе.

4. Если вы хотите отобразить Min(price) для API, он наиболее подходит для Phone API


Итак,

1. Удалите метакласс Phone из PriceSerializer

class PriceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Price
        fields = ('id', 'phone', 'price', 'date', 'market')

    phone = serializers.StringRelatedField()
    market = serializers.StringRelatedField()

Я не уверен, что вам известен механизм StringRelatedField(), поскольку вы ничего не сделали с вашим __str__() методом Price.

2. Создайте новый класс сериализатора для сериализации Price набор запросов

class PhoneSerializer(serializers.ModelSerializer):
    <b>min_price = serializers.IntegerField()</b>
    class Meta:
        model = Phone
        fields = '__all__'

Важно добавить новое поле min_price, чтобы захватить аннотированное значение Min() из набора запросов.

3. Создайте новый класс представления для отображения списка Phone

class PhoneAPI(generics.ListAPIView):
    <b>queryset = Phone.objects.annotate(min_price=Min('price__price'))</b>
    serializer_class = PhoneSerializer

Атрибут queryset должен быть аннотированным набор запросов.

4. подключить вид в urls.py

...