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

如何在Django中计算计数字段的累积求和

问题描述

我有一个用于记录事件及其发生日期的Event模型,需要完成两项计算:

  • 统计每日的事件数量
  • 计算事件随时间推移的累积总数

模型代码

class Event(models.Model):
    date = models.DateField()
    ...

尝试的代码及报错

统计每日事件数很简单,但计算累积求和时遇到问题,我尝试了以下代码:

query_set = Event.objects.values("date") \
                         .annotate(count=Count("date")) \
                         .annotate(cumcount=Window(Sum("count"), order_by="date"))              

运行后出现报错:

Cannot compute Sum('count'): 'count' is an aggregate

补充说明

理想情况下,希望用Django ORM实现与以下SQL语句等效的查询:

SELECT date,
       COUNT(date) as count,
       SUM(COUNT(date)) OVER(ORDER BY date) acc_count 
FROM event_event
GROUP BY date
解决方案

Django ORM不允许在Window函数中直接引用已通过annotate生成的聚合字段(比如这里的count),要实现目标SQL的逻辑,需要将聚合操作直接嵌套到Window的Sum中,代码如下:

from django.db.models import Count, Sum, Window, F

query_set = Event.objects.values("date") \
                         .annotate(
                             count=Count("date"),
                             acc_count=Window(
                                 Sum(Count("date")),
                                 order_by=F("date").asc()
                             )
                         )

这段代码会生成与目标SQL完全等效的查询:先按date分组统计每日事件数,再通过窗口函数计算从最早日期到当前日期的累积总数。

如果你的Django版本较低(低于3.2),嵌套聚合可能不被支持,此时可以通过子查询先获取每日计数,再基于子查询结果计算累积和:

from django.db.models import Count, Sum, Window, F, Subquery, OuterRef

# 定义子查询获取每日事件数
daily_counts = Event.objects.filter(date=OuterRef("date")) \
                            .values("date") \
                            .annotate(daily_count=Count("date")) \
                            .values("daily_count")

# 基于子查询结果计算累积总数
query_set = Event.objects.values("date") \
                         .annotate(count=Subquery(daily_counts)) \
                         .annotate(
                             acc_count=Window(
                                 Sum("count"),
                                 order_by=F("date").asc(),
                                 frame=RowRange(start=None, end=0)
                             )
                         ) \
                         .distinct()

distinct()用于去除重复的日期记录,确保每个日期只返回一条结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:51:29