Question
How can I add a new field avg_rating
to Musician
model which represents the avg of their albums rating (sum_of_rating / num_of_albums_in DB)
I have two models,
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
and serializer as,
class AlbumSerializer(serializers.ModelSerializer):
artist = serializers.StringRelatedField()
class Meta:
fields = '__all__'
model = Album
class MusicianSerializer(serializers.ModelSerializer):
albums = AlbumSerializer(many=True, source='album_set')
class Meta:
fields = '__all__'
model = Musician
views,
class AlbumViewset(ModelViewSet):
serializer_class = AlbumSerializer
queryset = Album.objects.all()
class MusicianViewset(ModelViewSet):
serializer_class = MusicianSerializer
queryset = Musician.objects.all()
and I got respons as,
[
{
"id": 1,
"albums": [
{
"id": 1,
"artist": "Musician object",
"name": "Scorpion",
"release_date": "2018-07-24",
"num_stars": 4
},
{
"id": 2,
"artist": "Musician object",
"name": "More Life",
"release_date": "2017-07-24",
"num_stars": 4
},
{
"id": 3,
"artist": "Musician object",
"name": "Views",
"release_date": "2017-07-24",
"num_stars": 3
},
{
"id": 4,
"artist": "Musician object",
"name": "Take Care",
"release_date": "2011-07-24",
"num_stars": 5
}
],
"first_name": "Drake",
"last_name": "Graham",
"instrument": "Sitar"
},
{
"id": 2,
"albums": [
{
"id": 5,
"artist": "Musician object",
"name": "Voicenotes",
"release_date": "2018-07-24",
"num_stars": 5
},
{
"id": 6,
"artist": "Musician object",
"name": "Nine Track Mind",
"release_date": "2016-07-24",
"num_stars": 5
}
],
"first_name": "Charlie",
"last_name": "Puth",
"instrument": "singer"
}
]
One of the easy and efficient solution is annotate the QuerySet
in get_queryset()
method as,
class MusicianViewset(ModelViewSet):
serializer_class = MusicianSerializer
queryset = Musician.objects.all()
class MusicianSerializer(serializers.ModelSerializer):
albums = AlbumSerializer(many=True, source='album_set')
class Meta:
fields = '__all__'
model = Musician
try this code by adding SerializerMethodField in serializer class
from django.db.models import Avg, F
class MusicianSerializer(serializers.ModelSerializer):
albums = AlbumSerializer(many=True, source='album_set')
avg_rating = serializers.SerializerMethodField()
class Meta:
model = Musician
fields = '__all__'
def get_avg_rating(self, obj):
# for particular musician get all albums and aggregate the all stars and return the avg_rating
return obj.album_set.aggregate(avgs=Avg(F('num_stars'))).get('avgs',None)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.