You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 08:25:46