问题
如何为avg_rating
模型添加一个新字段Musician
来表示其专辑评价的平均值(DB中的sum_of_rating / num_of_albums_in)
我有两个模型,
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()
和序列化器为
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
观看次数
class AlbumViewset(ModelViewSet):
serializer_class = AlbumSerializer
queryset = Album.objects.all()
class MusicianViewset(ModelViewSet):
serializer_class = MusicianSerializer
queryset = Musician.objects.all()
我得到了回应,
[
{
"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"
}
]
答案 0 :(得分:0)
一种简单有效的解决方案是在注释 QuerySet
get_queryset()
方法为
from django.db.models import Avg, F
class MusicianViewset(ModelViewSet):
serializer_class = MusicianSerializer
queryset = Musician.objects.all()
def get_queryset(self):
return super().get_queryset().annotate(avg_rating=Avg(F('album__num_stars')))
class MusicianSerializer(serializers.ModelSerializer):
albums = AlbumSerializer(many=True, source='album_set')
avg_rating = serializers.FloatField(read_only=True)
class Meta:
fields = '__all__'
model = Musician
答案 1 :(得分:0)
通过在序列化程序类中添加SerializerMethodField尝试此代码
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)