0

i have two simple models with random data about phones.

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)

I am able to send simple data via data the REST_framwork to my 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()

Now i wanted to use the annotate() method with the Min() function in a QuerySet. I wanted to display the minimum price of each phone. So i tried something like this:

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

of course this did not work. i followed along the server errors messages and ended with this:

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

My API shows me now this output, it´s not the min_price value, but at least something:

{"count":7,"next":null,"previous":null,"results":[{"name":"SAMSUNG Galaxy S10"},{"name":"SAMSUNG Galaxy S10 plus"},{"name":"SAMSUNG Galaxy S10e"},{"name":"SAMSUNG Galaxy S8"},{"name":"SAMSUNG Galaxy S8 Plus"},{"name":"SAMSUNG Galaxy S9"},{"name":"SAMSUNG Galaxy S9 plus"}]}

So i asked myself where to put .annotate(Min ? Or should i created a single ListCreateAPIView with queryset = Phone.objects.all() ? Is it possible to display the data of min_price without a new field in my serializers.py?

4
  • can you add the error traceback>? Commented Apr 29, 2019 at 1:01
  • If you try to find the min value from Price model, it won't return an expected result. Because, each row has only one price attribute, hence the Min(price) become price itself. Commented Apr 29, 2019 at 1:06
  • 1. With the serializers.py above, no error showed up. Only when i delete the lines wich includes class meta: model = Phone. Then the Error tells me that there is no Phone and price field. 2. ok i understand. That is why thought to go in my view / get_queryset with the "Phone.objects". Because then you have a certain Phone model "Samsung S10" for example and different prices. I guess i try to write a "ListCreateAPIView" only for Phone Model. Commented Apr 29, 2019 at 1:19
  • Yeah... But you should use the Phone Model with the serializer which you are intended to serialize them (phone querysets with Phone serializer). Also, should use the Phone Api along with them Commented Apr 29, 2019 at 1:39

1 Answer 1

1

I've already mentioned some points in comments. But, I'm going to repeat that here :(

1. If you try to find the min value from Price model, it won't return an expected result. Because, each row has only one price attribute, hence the Min(price) become price itself.

2. If you want to serialize a queryset of a particular model (say Price), you should have used the ModelSerializer defined with model=Price in metaclass of the serializer.

3. You can't use two Meta classes in one serializer.

4. If you wish to display the Min(price) to the api, it is most suited to the Phone API


So,

1. Remove the Phone meta class from PriceSerializer

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

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

I'm not sure you are aware of the StringRelatedField() mechanism since you didn't do anything to your __str__() method of the Price model.

2. Create a new serializer class for serializing the Price queryset

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

It's important to add a new field min_price to catch the annotated Min() value from the queryset.

3. Create a new view class to display the Phone list

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

The queryset attribute must be the annotated queryset.

4. wire up the view in urls.py

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.