Count 注释为所有字段添加不需要的 group by 语句

Count annotation adds unwanted group by statement for all fields

我想生成以下查询:

select id, (select count(*) from B where B.x = A.x) as c from A

Subquery 表达式应该很简单。除了我在我的计数查询中添加了一个 group by 语句,我无法摆脱它:

from django.contrib.contenttypes.models import ContentType

str(ContentType.objects.annotate(c=F('id')).values('c').query)
# completely fine query with annotated field
'SELECT "django_content_type"."id" AS "c" FROM "django_content_type"'

str(ContentType.objects.annotate(c=Count('*')).values('c').query)
# gets group by for every single field out of nowhere
'SELECT COUNT(*) AS "c" FROM "django_content_type" GROUP BY "django_content_type"."id", "django_content_type"."app_label", "django_content_type"."model"'

这使得结果为 [{'c': 1}, {'c': 1}, {'c': 1}, {'c': 1},...] 而不是 [{c:20}]。但是子查询必须只有一行结果才能使用。

由于查询应该在子查询中使用,我不能使用 .count().aggregate(),因为它们会立即求值并抱怨 OuterRef 表达式的使用。

子查询示例:

str(ContentType.objects.annotate(fields=Subquery(
    Field.objects.filter(model_id=OuterRef('pk')).annotate(c=Count('*')).values('c')
)).query)

生成

SELECT "django_content_type"."id",
       "django_content_type"."app_label",
       "django_content_type"."model",
       (SELECT COUNT(*) AS "c"
        FROM "meta_field" U0
        WHERE U0."model_id" = ("django_content_type"."id")
        GROUP BY U0."id", U0."model_id", U0."module", U0."name", U0."label", U0."widget", U0."visible", U0."readonly",
                 U0."desc", U0."type", U0."type_model_id", U0."type_meta_id", U0."is_type_meta", U0."multi",
                 U0."translatable", U0."conditions") AS "fields"
FROM "django_content_type"

预期查询:

SELECT "django_content_type"."id",
       "django_content_type"."app_label",
       "django_content_type"."model",
       (SELECT COUNT(*) AS "c"
        FROM "meta_field" U0
        WHERE U0."model_id" = ("django_content_type"."id")) AS "fields"
FROM "django_content_type"

更新:(添加来自评论中请求的真实应用程序的模型):

class Translation(models.Model):
    field = models.ForeignKey(MetaField, models.CASCADE)
    ref_id = models.IntegerField()
    # ... other fields

class Choice(models.Model):
    meta = models.ForeignKey(MetaField, on_delete=models.PROTECT)
    # ... other fields

我需要一个查询来获取每个选项可用的翻译数量,其中 Translation.field_id 指的是 Choice.meta_idTranslation.ref_id 指的是 Choice.id

没有外键的原因是并非所有元字段都是选择字段(例如,文本字段也可能有翻译)。我可以为每个 translatable 实体创建一个单独的 table,但是这个设置应该很容易与其中没有 group by 语句的计数子查询一起使用。

UPDATE 这是一个使用子查询的查询,应该接近您想要的结果:

str(ContentType.objects.annotate(fields=Subquery(
    Field.objects.filter(model_id=OuterRef('pk')).values('model').annotate(c=Count('pk')).values('c')
)).query)

我唯一做的就是添加 values('model') group_by 子句,这使得 Count('pk') 真正起作用,因为它将所有行聚合为一个。

当没有相关行时,它将 return null 而不是 0,您可以使用 Coalesce 函数或 Case ... When ... then

使用 Django ORM 无法实现您想要的确切查询,尽管您可以使用

获得相同的结果
Choice.objects.annotate(c=Count(
    'meta__translation',
    distinct=True,
    filter=Q(meta__translation__ref_id=F('id'))
))

或者看看django-sql-utils package, as also mentioned in this post