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

使用prefetch_related与聚合解决Django时序数据模型查询N+1问题

优化方案

你只需要直接从Vote模型出发做分组聚合,就能实现单条查询拿到所有需要的结果,完全解决N+1性能问题:

第一步:导入依赖

在views.py开头引入需要的Django数据库工具:

from django.db.models import Max, Min
from django.db.models.functions import TruncDate

第二步:重写视图逻辑

把原来的循环查询逻辑替换为下面的代码:

def index(request):
    # 单条查询完成所有按建议、按日期的分组聚合计算
    vote_agg_data = Vote.objects.values(
        "suggestion__title",
        vote_date = TruncDate("timestamp")
    ).annotate(
        daily_new_votes = Max("votes") - Min("votes")
    ).order_by("suggestion__title", "vote_date")

    # 整理成你需要的字典结构,完全在Python内存中处理,无额外数据库查询
    votes_per_day_per_suggestion = {}
    for item in vote_agg_data:
        title = item["suggestion__title"]
        vote_date = item["vote_date"]
        if title not in votes_per_day_per_suggestion:
            votes_per_day_per_suggestion[title] = {}
        votes_per_day_per_suggestion[title][vote_date] = item["daily_new_votes"]
    
    # 如果需要展示没有任何投票记录的建议,补充下面这段逻辑(只会多1次查询)
    # for title in Suggestion.objects.values_list("title", flat=True):
    #     if title not in votes_per_day_per_suggestion:
    #         votes_per_day_per_suggestion[title] = {}

    context = {"votes_per_day_per_suggestion": votes_per_day_per_suggestion}
    return render(request, "borgerforslag/index.html", context)

方案说明

  • 整个逻辑最多只会执行1-2次数据库查询,和原来的N+1查询相比性能提升非常明显,数据量越大优势越突出
  • 所有聚合计算都在数据库层完成,比Python循环逐行处理效率更高
  • 模板层不需要做任何修改,完全兼容你原来的输出逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:06:00