如何用Django查询构造器编写含Sum聚合字段的Case() SQL表达式
问题
需要用Django查询构造器重现以下SQL逻辑:
CASE WHEN sum(imps) = 0 THEN NULL ELSE SUM(total_expenses) / (sum(imps) / 1000) END as "cpm"
尝试了以下代码,但运行报错TypeError: '>' not supported between instances of 'Sum' and 'int':
MyModel.objects.annotate( cpm=Case( When( Sum("imps")>0, then=Sum("total_expenses") / Sum("imps"), ), default=0, output_field=FloatField(), ) )
期望用类似total_imps__sum__gt=0的字段查询方式解决,不希望通过先注解total_imps=Sum("imps")再用total_imps__gt=0的冗余方式实现。
解决方案
可以用Django的Q()查询结合聚合筛选语法,直接在When的条件中判断聚合值,无需额外注解:
from django.db.models import Case, When, Sum, FloatField, Q MyModel.objects.annotate( cpm=Case( When( Q(imps__sum__gt=0), then=Sum("total_expenses") / (Sum("imps") / 1000), ), default=None, # 对应原SQL中的NULL逻辑 output_field=FloatField(), ) )
关键说明:
Q(imps__sum__gt=0)是Django ORM支持的聚合筛选写法,能正确转换为SQL中的sum(imps) > 0条件,避免了直接用Sum("imps")>0引发的类型错误- 将
default=0改为default=None,和原SQL的THEN NULL逻辑完全匹配 - 还原原SQL的计算式
SUM(total_expenses) / (sum(imps) / 1000),修正了原尝试代码中缺少除以1000的问题
这样就能在不创建多余注解的前提下,完美复现目标SQL的逻辑。
内容的提问来源于stack exchange,提问作者Cal El
相关产品推荐
相关产品推荐

