如何计算Django模型评论评分平均值并返回给REST API
实现方案
方案1:模型层新增计算属性(适合多处复用场景)
该方式将计算逻辑封装在Gigs模型中,所有调用Gigs实例的场景都可以直接复用计算逻辑,不需要重复编码。
# models.py from django.db import models from django.db.models import Avg class Gigs(models.Model): # 保留你原有Gigs模型的全部字段,比如标题、价格、描述等 title = models.CharField(max_length=120) # 其他原有字段... @property def average_rating(self): # 聚合计算关联评论的评分平均值 avg_result = self.reviews.aggregate(avg=Avg('rating'))['avg'] # 没有评论时默认返回0,可按需调整保留的小数位数 return round(avg_result, 1) if avg_result else 0 class Reviews(models.Model): # 注意外键要设置related_name为reviews,和上面聚合时的调用名对应 gig = models.ForeignKey(Gigs, on_delete=models.CASCADE, related_name="reviews") rating = models.SmallIntegerField() # 假设是1-5分的整数评分 # 其他原有评论字段...
接下来修改序列化器,把平均评分字段加入返回值:
# serializers.py from rest_framework import serializers from .models import Gigs class GigsSerializer(serializers.ModelSerializer): average_rating = serializers.FloatField(read_only=True) class Meta: model = Gigs # 把average_rating加入你原有fields列表即可,不需要修改其他逻辑 fields = ['id', 'title', 'average_rating', ...]
注意:该方式查询Gigs列表时会产生N+1查询问题,更适合单条Gig详情接口的场景,如果是列表查询推荐用方案2。
方案2:视图层聚合查询(列表查询性能更优)
如果需要在Gigs列表接口返回平均评分,推荐在查询时一次性聚合所有数据,仅需要1次关联查询,性能远高于方案1。
不需要修改模型代码,直接调整视图层的查询集即可:
# views.py from django.db.models import Avg from rest_framework import viewsets from .models import Gigs from .serializers import GigsSerializer class GigsViewSet(viewsets.ModelViewSet): # 原有查询集基础上增加annotate聚合逻辑 queryset = Gigs.objects.all().annotate( average_rating=Avg('reviews__rating') ) serializer_class = GigsSerializer
序列化器的修改和方案1完全一致,直接把average_rating加入序列化字段列表即可。
提示:如果需要固定返回小数位数,可以在序列化器字段中添加验证逻辑,或者用数据库函数直接在聚合时格式化结果。
验证效果
修改完成后调用Gigs的详情或列表接口,返回值中会自动新增average_rating字段,值为对应Gig的所有评论评分平均值。
内容的提问来源于stack exchange,提问作者Ruma
相关产品推荐
相关产品推荐

