Reputation: 25584
I'm using DRF for the first time. I've been reading the documentation pages but no clue on how to do this.
I have two models, the AdPrice Model make reference to the Ad Model. I need to list the various prices for an Ad.
My question is: How can I get a list of Ads like this?
[
{
"title": "Some long title for Ad1",
"name": "Name Ad1",
"prices": {
{ "name": "price now", "price": 200 },
{ "name": "price later", "price": 300 }
}
},
]
models.py
class Ad(models.Model):
title = models.CharField(max_length=250)
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class AdPrice(models.Model):
ad = models.ForeignKey(Ad)
name = models.CharField(max_length=50)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return self.name
serializers.py
class AdPriceSerializer(serializers.Serializer):
name = serializers.CharField(max_length=50)
price = serializers.DecimalField(max_digits=6, decimal_places=2)
class Meta:
model = AdPrice
class AdSerializer(serializers.Serializer):
title = serializers.CharField(max_length=250)
name = serializers.CharField(max_length=100)
prices = AdPriceSerializer(many=True)
views.py
class AdViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = Ad.objects.all().order_by('-date_inserted')
serializer_class = AdSerializer
When I try the code above I got this error:
AttributeError at /ads/
Got AttributeError when attempting to get a value for field `prices` on serializer `AdSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Ad` instance.
Original exception text was: 'Ad' object has no attribute 'prices'.
Any clues on how to solve this?
Best Regards, André Lopes.
Upvotes: 2
Views: 1944
Reputation: 1020
From what I am seeing here you're missing the read_only=True
and class meta
within the
class AdSerializer(serializers.Serializer):
title = serializers.CharField(max_length=250)
name = serializers.CharField(max_length=100)
prices = AdPriceSerializer(many=True, read_only=True)
class Meta:
model = Ad
and in order to also avoid n+1 query problem you'd want to override the queryset
to be
from django.db.models import Prefetch
queryset=Ad.objects.all().order_by('-date_inserted').prefetch_related(Prefetch('adprice_set', queryset=AdPrice.objects.filter(ad_id__in=queryset), to_attr='prices'))
Since Django has a lazy ORM, it means that for every Ad you have in there, it would make another query to get the AdPrices. So for 100 ads, it would make 200 queries. Not the most efficient solution, right?. With prefetch you're making that as short as only two queries, one to get all the ads
and the other one to get all the relevant adprices
.
Upvotes: 2