在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
相关产品推荐
相关产品推荐

