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

Django ORM如何不使用.raw()实现窗口函数子查询后分组聚合

问题解决方法

错误原因

你遇到的报错是因为Django ORM默认会将连续的annotate操作合并到同一个SELECT查询层级,导致窗口函数被嵌套进聚合函数的参数中,这不符合SQL的执行逻辑:聚合函数在GROUP BY阶段执行,而窗口函数的执行时机晚于聚合,因此不允许在聚合函数内调用窗口函数。

正确实现方式

我们可以通过将窗口函数逻辑封装为子查询,再在外层执行分组聚合的方式实现需求,全程不需要调用.raw(),示例代码如下:

from django.db.models import F, Max, Avg, Window
from django.db.models.query import QuerySet

# 1. 构造内层子查询:按part_id分区计算max_count
inner_qs = TableOne.objects.annotate(
    max_count=Window(
        expression=Max('count'),
        partition_by=F('part_id')
        # 此处order_by和partition_by字段一致,可省略不写
    )
).values('col_id', 'max_count') # 仅保留后续聚合需要的字段

# 2. 外层查询:基于子查询结果分组求平均值
result_qs = QuerySet(model=TableOne).from_queryset(inner_qs, alias='inner_temp')\
    .values('col_id')\
    .annotate(avg_max_count=Avg('max_count'))

# 执行查询获取结果,返回格式为 [{'col_id': xx, 'avg_max_count': xx}, ...]
result = list(result_qs)

实现说明

  • from_queryset方法会将内层查询作为临时表嵌套进外层查询的FROM子句中,完全匹配你给出的原生SQL结构
  • 如果你需要关联查询Col表的其他字段,可以在外层查询中使用col_id__name这类跨表字段名访问
  • 该方案所有逻辑都在数据库层面执行,性能和原生SQL基本一致,适合大数据量场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 02:27:01