这是一个前沿的功能,我目前正在解决这个问题并迅速流血.我想在现有的查询集上注释子查询聚合.在1.11之前执行此操作要么意味着自定义SQL,要么锤击数据库. Here’s the documentation for t
from django.db.models import OuterRef, Subquery, Sum comments = Comment.objects.filter(post=OuterRef('pk')).values('post') total_comments = comments.annotate(total=Sum('length')).values('total') Post.objects.filter(length__gt=Subquery(total_comments))
他们在总体上注释,这对我来说似乎很奇怪,但无论如何.
我正在努力解决这个问题,所以我正在把它煮回来,回到我有数据的最简单的现实世界的例子.我有停车场,其中包含许多空间.使用Book→Author如果这让你更快乐,但是 – 现在 – 我只想使用Subquery *来注释相关模型的计数.
spaces = Space.objects.filter(carpark=OuterRef('pk')).values('carpark') count_spaces = spaces.annotate(c=Count('*')).values('c') Carpark.objects.annotate(space_count=Subquery(count_spaces))
这给了我一个可爱的ProgrammingError:用作表达式的子查询返回的多行,在我的脑海中,这个错误非常有意义.子查询返回带有注释总计的空格列表.
这个例子表明会发生某种魔法,我最终会得到一个我可以使用的数字.但这不是在这里发生的?如何对聚合子查询数据进行注释?
嗯,有什么东西被添加到我的查询的SQL中……
我建造了一个新的停车场/太空模型,它的工作原理.所以下一步是弄清楚我的SQL中毒了什么.根据Laurent的建议,我看了一下SQL并尝试使它更像是他们在答案中发布的版本.这就是我发现真正问题的地方:
SELECT "bookings_carpark".*, (SELECT COUNT(U0."id") AS "c" FROM "bookings_space" U0 WHERE U0."carpark_id" = ("bookings_carpark"."id") GROUP BY U0."carpark_id", U0."space" ) AS "space_count" FROM "bookings_carpark";
我突出了它,但它是子查询的GROUP BY … U0.“space”.由于某种原因,它正在重新调整.调查仍在继续.
编辑2:好的,只是查看子查询SQL我可以通过☹看到第二组
In [12]: print(Space.objects_standard.filter().values('carpark').annotate(c=Count('*')).values('c').query) SELECT COUNT(*) AS "c" FROM "bookings_space" GROUP BY "bookings_space"."carpark_id", "bookings_space"."space" ORDER BY "bookings_space"."carpark_id" ASC, "bookings_space"."space" ASC
编辑3:好的!这两个模型都有排序顺序.这些正在传递到子查询.正是这些订单膨胀了我的查询并打破了它.
我想这可能是Django中的一个错误但是在这两个模型上删除了Meta-order_by,有没有什么方法可以在查询时解除查询?
*我知道我可以为这个例子注释一个Count.我使用它的真正目的是一个更复杂的过滤器计数,但我甚至无法实现这一点.
也可以创建Subquery的子类,以更改它输出的SQL.例如,您可以使用:class SQCount(Subquery): template = "(SELECT count(*) FROM (%(subquery)s) _count)" output_field = models.IntegerField()
然后,就像使用原始Subquery类一样使用它:
spaces = Space.objects.filter(carpark=OuterRef('pk')).values('pk') Carpark.objects.annotate(space_count=SQCount(spaces))
你可以使用这个技巧(至少在postgres中)使用一系列聚合函数:我经常使用它来构建一个值数组,或者总结它们.