Django使用表达式聚合查询

Ped*_*eck 7 python sql django django-1.3

我有一个模型XYZ,我需要获得给定查询集的字段a,b和表达式x/y的最大值.

它适用于田野.就像是:

>>> XYZ.all().aggregate(Max('a'))

... {'a__max': 10}
Run Code Online (Sandbox Code Playgroud)

但是,我无法找到表达式的方法.尝试类似的东西:

>>> XYZ.all().aggregate(Max('x/y'))
Run Code Online (Sandbox Code Playgroud)

给出错误:

*** FieldError: Cannot resolve keyword 'x/y' into field. Choices are: a, b, x, y, id
Run Code Online (Sandbox Code Playgroud)

尝试类似的东西:

>>> XYZ.all().aggregate(Max(F('x')/F('y')))
Run Code Online (Sandbox Code Playgroud)

给出错误:

*** AttributeError: 'ExpressionNode' object has no attribute 'split'
Run Code Online (Sandbox Code Playgroud)

甚至是这样的:

XYZ.all().extra(select={'z':'x/y'}).aggregate(Max('z'))
Run Code Online (Sandbox Code Playgroud)

也不起作用,并给出与上面相同的错误:

FieldError: Cannot resolve keyword 'z' into field. Choices are: a, b, x, y, id
Run Code Online (Sandbox Code Playgroud)

我发现这样做的一个黑客是:

XYZ.all().extra(select={'z':'MAX(x/y)'})[0].z
Run Code Online (Sandbox Code Playgroud)

这实际上是有效的,因为它生成了正确的SQL,但它令人困惑,因为我确实在z atttribute获得了正确的值,但没有正确的实例,即具有该最大值的实例.

当然,我也可以使用带有extra()和order_by()的原始查询或技巧,但是我真的没理由Django以一种很好的方式支持聚合查询,但不能支持表达式甚至有自己的F表达式.

有什么办法吗?

okm*_*okm 6

在SQL中,你想要的实际上是

SELECT x/y, * FROM XYZ ORDER BY x/y DESC LIMIT 1;
# Or more verbose version of the #1
SELECT x/y, id, a, b, x, y FROM XYZ GROUP BY x/y, id, a, b, x, y ORDER BY x/y DESC LIMIT 1;
# Or
SELECT * FROM XYZ WHERE x/y = (SELECT MAX(x/y) FROM XYZ) LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

因此在Django ORM中:

XYZ.objects.extra(select={'z':'x/y'}).order_by('-z')[0]
# Or
XYZ.objects.extra(select={'z':'x/y'}).annotate().order_by('-z')[0]
# Or x/y=z => x=y*z
XYZ.objects.filter(x=models.F('y') * XYZ.objects.extra(select={'z':'MAX(x/y)'})[0].z)[0]
Run Code Online (Sandbox Code Playgroud)

版本

XYZ.all().extra(select={'z':'MAX(x/y)'})[0].z
Run Code Online (Sandbox Code Playgroud)

没有正确的x,y和实例,因为MAX函数在所有行之间进行求值,当没有时GROUP BY,因此返回的QuerySet中的所有实例都具有相同的zas 值MAX(x/y).