这是一个前沿功能,我目前一直在使用它,但很快就会消失。我想将子查询聚合注释到现有查询集上。在 1.11 之前执行此操作意味着自定义 SQL 或破坏数据库。 Here's the documentation for this ,以及它的例子:
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))
他们在聚合上注释,这对我来说似乎很奇怪,但无论如何。
我正在努力解决这个问题,所以我将它直接煮回到我有数据的最简单的真实示例。我有 Carpark
,其中包含许多 Space
。使用 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: more than one row returned by a subquery used as an expression
在我看来,这个错误非常有意义。子查询返回带有注释总数的空格列表。
这个例子表明会发生某种魔法,我最终会得到一个我可以使用的数字。但这不是在这里发生的吗?如何对聚合子查询数据进行注释?
嗯,正在向我的查询的 SQL 添加一些内容...
我构建了一个新的 parking 场/空间模型并且它起作用了。所以下一步是弄清楚是什么让我的 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"<strong>, U0."space"</strong>
)
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 中不是必需的)。
我只需要从模型中删除规定的元顺序。您可以通过向子查询添加一个空的 .order_by()
来做到这一点。在我的代码术语中,这意味着:
from django.db.models import Count, OuterRef, Subquery
spaces = Space.objects.filter(carpark=OuterRef('pk')).order_by().values('carpark')
count_spaces = spaces.annotate(c=Count('*')).values('c')
Carpark.objects.annotate(space_count=Subquery(count_spaces))
那行得通。棒极了。太烦人了。
关于Django 1.11 注释子查询聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42543978/