Django ORM 在注释多个聚合列时删除不需要的组

tar*_*ghs 3 sql django orm django-models django-orm

我想在 django ORM 中创建一个类似这样的查询。

SELECT COUNT(CASE WHEN myCondition THEN 1 ELSE NULL end) as numyear
FROM myTable
Run Code Online (Sandbox Code Playgroud)

以下是我编写的 djang ORM 查询

year_case = Case(When(added_on__year = today.year, then=1), output_field=IntegerField())

qs = (ProfaneContent.objects
                    .annotate(numyear=Count(year_case))
                    .values('numyear'))
Run Code Online (Sandbox Code Playgroud)

这是由 django orm 生成的查询。

SELECT COUNT(CASE WHEN "analyzer_profanecontent"."added_on" BETWEEN 2020-01-01 00:00:00+00:00 AND 2020-12-31 23:59:59.999999+00:00 THEN 1 ELSE NULL END) AS "numyear" FROM "analyzer_profanecontent" GROUP BY "analyzer_profanecontent"."id"
Run Code Online (Sandbox Code Playgroud)

所有其他事情都很好,但是 django在最后放置了一个GROUP BY导致多行和错误答案。我根本不想那样。现在只有一列,但我会放置更多这样的列。

根据评论进行编辑 我将使用 qs 变量来获取我的分类在当前年、月、周的值。

更新 根据我来到这里的评论和答案,让我澄清一下。我只想在数据库端执行此操作(显然使用 Django ORM 而不是 RAW SQL)。它是一个简单的 sql 查询。由于数据可能太大,在 Python 端做任何事情都是低效的。这就是为什么我希望数据库根据 CASE 条件获取记录的总和。我将来会添加更多这样的列,所以像 len() 或 .count 这样的东西将不起作用。

我只想使用 Django ORM 创建上面提到的查询(没有自动附加的 GROUP BY)。

小智 9

在注释中使用聚合时,django 需要进行某种分组,否则默认为主键。因此,您需要.values().annotate(). 请参阅 Django 文档

但是要完全删除组,您可以使用静态值,并且 django 足够聪明,可以完全删除它,因此您可以使用 ORM 查询获得结果,如下所示:

year_case = Case(When(added_on__year = today.year, then=1), output_field=IntegerField())

qs = (ProfaneContent.objects
                    .annotate(dummy_group_by = Value(1))
                    .values('dummy_group_by')
                    .annotate(numyear=Count(year_case))
                    .values('numyear'))
Run Code Online (Sandbox Code Playgroud)

  • 来自https://docs.djangoproject.com/en/4.1/topics/db/aggregation/:'与aggregate()不同,annotate()不是一个终止子句。annotate() 子句的输出是一个 QuerySet;可以使用任何其他 QuerySet 操作来修改此 QuerySet,包括 filter()、order_by(),甚至对 annotate() 的其他调用。 (3认同)