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

在Django中不使用原生SQL实现带GROUP BY的子查询平均值计算

解决Django中无原生SQL计算分组子查询平均值的问题

嘿,我来帮你搞定这个问题!你已经用values和annotate拿到了分组求和的子查询,那接下来求平均值其实只需要注意字段引用的正确性就好,我给你详细拆解步骤:

正确实现步骤

1. 构建分组求和的子查询

首先,确保给你的求和结果指定一个明确的别名,这样后续聚合时能准确引用:

from django.db.models import Sum, Avg

# 按date分组,计算每日总卡路里,别名设为daily_sum
daily_calories = ProductsEaten.objects.values('date').annotate(daily_sum=Sum('calories'))

这一步对应的SQL就是你示例里的子查询:

SELECT date, SUM(calories) AS daily_sum FROM products_eaten GROUP BY date

2. 对分组结果求平均值

直接在这个子查询QuerySet上调用aggregate,引用你刚才设置的别名daily_sum即可:

# 计算每日卡路里的平均值,结果会以字典形式返回,取对应的键值
avg_daily_calories = daily_calories.aggregate(avg_daily=Avg('daily_sum'))['avg_daily']

这一步会生成和你目标SQL一致的逻辑:先执行子查询,再对子查询的daily_sum列求平均值。

为什么你之前的尝试失败?

大概率是字段引用错误:

  • 如果你在annotate时没有指定别名(比如直接写annotate(Sum('calories'))),Django会自动生成默认字段名calories__sum,这时候你需要用这个名字来聚合:
    daily_calories = ProductsEaten.objects.values('date').annotate(Sum('calories'))
    avg_daily_calories = daily_calories.aggregate(avg_daily=Avg('calories__sum'))['avg_daily']
    
  • 另外,aggregate是对整个QuerySet做聚合,返回的是字典,你需要通过键名获取结果,不能直接把它当成单个值使用。

进阶:用Subquery显式构造子查询(复杂场景适用)

如果后续需要更复杂的关联逻辑,也可以用Subquery显式定义子查询再聚合:

from django.db.models import Sum, Avg, Subquery

# 定义子查询,只保留daily_sum字段
subquery = ProductsEaten.objects.values('date').annotate(daily_sum=Sum('calories')).values('daily_sum')

# 在外层查询中聚合子查询结果
avg_daily_calories = ProductsEaten.objects.aggregate(avg_daily=Avg(Subquery(subquery)))['avg_daily']

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 17:57:36