Django Rest Framework序列化器获取关联评分的数量与平均值方法
实现方式
方法一:用SerializerMethodField直接计算
适合数据量较小的场景,直接在序列化器里通过关联对象计算总数和平均值。
假设你的模型结构如下:
from django.db import models class Post(models.Model): title = models.CharField(max_length=200) # 其他业务字段 class PostRating(models.Model): post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='ratings') score = models.IntegerField() # 假设评分是1-5的整数 # 其他字段
修改PostSerializer:
from rest_framework import serializers from .models import Post class PostSerializer(serializers.ModelSerializer): # 保留原有的ratings字段(如果前端需要展示具体评分项) ratings = serializers.PrimaryKeyRelatedField(many=True, read_only=True) # 新增评分统计字段 rating_count = serializers.SerializerMethodField() rating_average = serializers.SerializerMethodField() def get_rating_count(self, obj): return obj.ratings.count() def get_rating_average(self, obj): # 处理无评分的情况,避免除以0报错 if obj.ratings.exists(): return round(obj.ratings.aggregate(avg=models.Avg('score'))['avg'], 2) return 0.0 # 也可以返回None,根据前端需求调整 class Meta: model = Post fields = ['id', 'title', 'ratings', 'rating_count', 'rating_average']
方法二:用QuerySet.annotate提前聚合(推荐)
如果数据量较大,方法一会触发N+1查询(每个Post单独查一次评分数据),性能拉胯。这种情况建议在查询Post时提前聚合计算,序列化器直接映射字段即可。
在视图层修改查询集:
from django.db.models import Count, Avg from django.db.models.functions import Coalesce from rest_framework import viewsets from .models import Post from .serializers import PostSerializer class PostViewSet(viewsets.ReadOnlyModelViewSet): queryset = Post.objects.annotate( rating_count=Count('ratings'), # 用Coalesce处理无评分时的空值,直接返回0.0 rating_average=Coalesce(Avg('ratings__score'), 0.0) ).all() serializer_class = PostSerializer
对应修改序列化器,直接读取聚合好的字段:
from rest_framework import serializers from .models import Post class PostSerializer(serializers.ModelSerializer): ratings = serializers.PrimaryKeyRelatedField(many=True, read_only=True) # 直接映射annotate生成的字段,无需额外计算 rating_count = serializers.IntegerField(read_only=True) rating_average = serializers.FloatField(read_only=True) class Meta: model = Post fields = ['id', 'title', 'ratings', 'rating_count', 'rating_average']
内容的提问来源于stack exchange,提问作者crawlingdev
相关产品推荐
相关产品推荐

