我有一个模型XYZ,我需要获得给定查询集的字段a,b和表达式x / y的最大值。
它适用于田野。类似的东西:
>>> XYZ.all().aggregate(Max('a'))
... {'a__max': 10}
但是,我无法找到表达式的方法。尝试类似的事情:
>>> XYZ.all().aggregate(Max('x/y'))
给出错误:
*** FieldError: Cannot resolve keyword 'x/y' into field. Choices are: a, b, x, y, id
尝试类似:
>>> XYZ.all().aggregate(Max(F('x')/F('y')))
给出错误:
*** AttributeError: 'ExpressionNode' object has no attribute 'split'
甚至可以这样:
XYZ.all().extra(select={'z':'x/y'}).aggregate(Max('z'))
也不起作用,并给出与上述相同的错误:
FieldError: Cannot resolve keyword 'z' into field. Choices are: a, b, x, y, id
我发现这样做的一个黑客是:
XYZ.all().extra(select={'z':'MAX(x/y)'})[0].z
这实际上是有效的,因为它生成了正确的SQL,但它让人感到困惑,因为我确实在z atttribute获得了正确的值,而不是正确的实例,即具有该最大值的实例。
当然,我也可以使用带有extra()和order_by()的原始查询或技巧,但对我来说,Django一路上以一种很好的方式支持聚合查询真的没有意义,但是即使使用自己的F表达式也不支持表达式。
有什么办法吗?
答案 0 :(得分: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;
因此在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]
版本
XYZ.all().extra(select={'z':'MAX(x/y)'})[0].z
没有正确的x,y和实例,因为MAX
函数在没有GROUP BY
的情况下在所有行中进行求值,因此返回的QuerySet中的所有实例都具有相同的值{{ 1}}为z
。
答案 1 :(得分:2)
使用F()
对象的示例应该可以正常使用,因为Django 1.8:
XYZ.all().aggregate(Max(F('x')/F('y')))
有一个代码段演示了Django aggregation cheat sheet中Sum()
和F()
个对象的汇总:
Book.objects.all().aggregate(price_per_page=Sum(F('price')/F('pages'))
答案 2 :(得分:0)
对于低于1.8的版本,您可以使用此(未记录的)方式实现相同的目的。
Book.objects.all().aggregate(price_per_page=Sum('price_per_page',
field='book_price/book_pages'))
这适用于Postgres,我不了解MySQL。
来源:Django Aggregation: Summation of Multiplication of two fields
答案 3 :(得分:-3)
我认为你应该单独获得最大值
result = XYZ.aggregate(Max('x'), Max('y'))
然后划分两个字段
result['x__max'] \ result['y__max']