I have two models. Fiction and Review model. They are the following:
class Fiction(models.Model):
"""
Model that encopasses a Movie, TV Series, book or similar
"""
MOVIE = 1
TV_SERIES = 2
BOOK = 3
PODCAST = 4
TYPE = (
(MOVIE, 'Movie'),
(TV_SERIES, 'TV-Series'),
(BOOK, 'Book'),
(PODCAST, 'Podcast')
)
title = models.CharField(max_length=50)
description = models.CharField(max_length=200)
active = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
platform = models.ForeignKey(
StreamPlatform,
on_delete=models.SET_NULL,
related_name='fictions',
null = True
)
type = models.PositiveSmallIntegerField(
choices = TYPE,
default = MOVIE
)
def __str__(self):
return self.title
and
class Review(models.Model):
"""
model for fiction reviews from users
"""
rating = models.PositiveSmallIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
fiction = models.ForeignKey(Fiction, on_delete=models.CASCADE, related_name="reviews")
description = models.CharField(max_length=200, null = True, blank =True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.rating) + " | " + str(self.fiction)
class Meta:
ordering = ['-created']
and also two serializers for fiction
class FictionSerializer(serializers.ModelSerializer):
"""
serializer for Movie model
"""
class Meta:
model = Fiction
fields = "__all__"
and for review
class ReviewSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = ['rating', 'fiction', 'description']
I want to be able to display the rating of the review inside the fiction serializers. I tried something like:
rating = serializers.ReadOnlyField(source='reviews.rating')
but it didnt work. Anyone has an idea?
Since you added reviews
as a related name, you can use that.
Here is a working example for you. (I've created a small project for this, so this definitely works)
class ReviewRatingSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = ('rating', )
class FictionSerializer(serializers.ModelSerializer):
"""
serializer for Movie model
"""
reviews = ReviewRatingSerializer(many=True)
class Meta:
model = Fiction
fields = "__all__"
This might cause lots of database queries if you want to return lots of Fiction items at once.
To fix that, you should use prefetch_related
in your views.py
Here is a simple example for a list view.
class GetFictionMovies(ListAPIView):
pagination_class = None
serializer_class = FictionSerializer
def get_queryset(self):
queryset = Fiction.objects.all().prefetch_related('reviews')
return queryset
Output will be similar to this.
[
{
"id": 1,
"reviews": [
{
"rating": 3
},
{
"rating": 4
}
],
"title": "Starwars",
"description": "asdasd",
"active": true,
"created": "2021-06-27T16:28:55.521748Z",
"type": 1
},
{
"id": 2,
"reviews": [
{
"rating": 5
},
{
"rating": 2
}
],
"title": "LOTR",
"description": "asdasd",
"active": true,
"created": "2021-06-27T16:29:03.227639Z",
"type": 1
},
{
"id": 3,
"reviews": [
{
"rating": 4
},
{
"rating": 3
}
],
"title": "GODFATHER",
"description": "asdasd",
"active": true,
"created": "2021-06-27T16:34:45.171444Z",
"type": 1
}
]
My advice for you is to always check for number of queries made to the db and try to avoid duplicate calls to the db.