我想生成以下查询:
select id, (select count(*) from B where B.x = A.x) as c from A
对于子查询表达式来说,这应该足够简单了,除了我得到了一个添加到计数查询中的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_id
和Translation.ref_id
指的是Choice.id
。
没有外键的原因是不是所有的 meta字段都是选择字段(例如,文本字段也可能有翻译)。我可以为每个可翻译的实体创建一个单独的表,但这种设置应该很容易与没有group by
语句的count子查询一起使用。
2条答案
按热度按时间o7jaxewo1#
UPDATE下面是一个使用子查询的查询,它应该接近您所需的内容:
我所做的唯一一件事就是添加了
values('model')
group_by子句,这使得Count('pk')
实际上可以工作,因为它将所有行聚合为一行。当没有相关行时,它将返回
null
而不是0
,您可以使用Coalesce
函数或Case ... When ... then
将其转换为0。使用DjangoORM不可能实现您想要的精确查询,尽管可以使用
或者看看django-sql-utils包,this post中也提到了这一点。
rhfm7lfc2#
这是一个有点肮脏的黑客,但在深入研究Django的ORM代码后,我发现以下代码对我来说非常有效(使用您自己的子查询):
关键是将group_by设置为True,这样就可以去掉SQL中不需要的group_by子句。
我对此并不满意,因为它依赖于Django未记录的行为来工作。但我可以接受它,我更不满意在子查询中使用直接SQL的可维护性...