Django 1.11 注释子查询聚合

标签 django django-aggregation django-annotate django-subquery

这是一个前沿功能,我目前一直在使用它,但很快就会消失。我想将子查询聚合注释到现有查询集上。在 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/

相关文章:

django - 502 错误网关 (nginx/1.10.3 (Ubuntu))

python - Django 注释外键的外键计数

Django- Group by 和 Count by unique 在一起

python - 根据条件使用外键计数注释 Django 查询集

python - 如果字段值在外部列表中,Django 注释 bool 值

django - 使用 Django 基于类的 View ,如果 request.is_ajax 如何返回不同的模板

python - 反馈表 Django

Django 3.0 + Channels + ASGI + TokenAuthMiddleware

django - 如何在 Django 中创建引用两个相关模型的注释

django - 如何以天为单位注释日期时间的差异