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

如何在Django Rest Framework中避免按模型属性排序时重复计算?

社交应用投票统计性能优化方案

核心问题分析

当前代码存在三个关键性能瓶颈:

  1. score 属性遍历所有PostVote数据再筛选,完全未利用数据库查询优化
  2. 排序时将QuerySet转为Python列表后排序,无法借助数据库索引加速
  3. 序列化器重复调用计算方法,触发大量N+1查询

优化步骤

1. 用数据库聚合替代Python层面的遍历/查询

直接在数据库层面通过annotate一次性计算所有需要的统计值,避免多次查询:

修改视图的get_queryset方法

from django.db.models import Sum, Count, Case, When, IntegerField

class ListCreatePostAPIView(ListCreateAPIView):
    serializer_class = PostSerializer
    permission_classes = (IsGoodUser | IsAdminUser,)

    def get_queryset(self):
        return Post.objects.filter(user__isnull=False).annotate(
            # 计算总得分:vote字段求和
            score=Sum('postvote__vote'),
            # 计算点赞数:统计vote=1的记录
            num_upvotes=Count(Case(
                When(postvote__vote=1, then=1),
                output_field=IntegerField()
            )),
            # 计算点踩数:统计vote=-1的记录
            num_downvotes=Count(Case(
                When(postvote__vote=-1, then=1),
                output_field=IntegerField()
            ))
        ).order_by('-score')

2. 简化序列化器,直接使用数据库注解字段

无需再调用模型的计算方法,直接映射annotate生成的字段:

class PostSerializer(serializers.ModelSerializer):
    # 直接使用annotate生成的字段,无需SerializerMethodField
    score = serializers.IntegerField(read_only=True)
    num_upvotes = serializers.IntegerField(read_only=True)
    num_downvotes = serializers.IntegerField(read_only=True)

    class Meta:
        model = Post
        fields = (
            "score",
            "num_upvotes",
            "num_downvotes",
            # 补充你需要的其他Post字段
        )

3. 清理模型中的冗余计算逻辑

既然已用数据库聚合完成统计,可移除模型中低效的计算方法:

class Post(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    
    # ... 保留其他业务字段,移除以下冗余方法/属性
    # @property
    # def score(self): ...
    # def get_num_upvotes(self): ...
    # def get_num_downvotes(self): ...

优化效果说明

  • 减少查询次数:原逻辑每个Post会触发3次额外查询,现在单次数据库查询完成所有统计和排序
  • 利用数据库性能:数据库对聚合、排序有专门优化,效率远高于Python层面的遍历计算
  • 降低内存消耗:无需将所有PostVote数据加载到内存,仅返回统计结果

内容的提问来源于stack exchange,提问作者rd360

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:45:31