这是一个孤立的 ORM 查询:
Purpose.objects.annotate(
conversation_count=SubqueryCount(
Conversation.objects.filter(goal_slugs__contains=[OuterRef("slug")]).values("id")
)
)
Run Code Online (Sandbox Code Playgroud)
其中 SubqueryCount 是:
from django.db.models import IntegerField
from django.db.models.expressions import Subquery
class SubqueryCount(Subquery):
template = "(SELECT count(*) FROM (%(subquery)s) _count)"
output_field = IntegerField()
Run Code Online (Sandbox Code Playgroud)
运行该查询时,将使用以下 sql(通过 djdt 解释):
SELECT
"taxonomy_purpose"."id",
"taxonomy_purpose"."slug",
(
SELECT count(*)
FROM (
SELECT U0."id"
FROM "conversations_conversation" U0
WHERE U0."goal_slugs" @> ARRAY['ResolvedOuterRef(slug)']::varchar(100)[]
) _count
) AS "conversation_count"
FROM "taxonomy_purpose"
Run Code Online (Sandbox Code Playgroud)
注意ResolvedOuterRef(slug)作为字符串注入到 ARRAY 查找中。我做错了什么,还是应该将此报告为错误?如果这是一个错误,是否有已知的解决方法(可能创建自定义 OuterRef 类)?
我没有你的模型或任何价值,所以我无法检查我所说的是否有效。
我假设您使用的是 Postgres 和 Django 2.2
主要问题是 django[Anything]当Anything不是一个简单的字符串时在转换方面有问题。它不适用于 OuterRef,也不适用于 F 表达式(这是我过去用更简单的查询重现的)
所以我要做的是使用一个函数直接在 Postgres 中将其转换为数组:
from django.db.models import Func
Purpose.objects.annotate(
conversation_count=SubqueryCount(
Conversation.objects.filter(
goal_slugs__contains=Func(
OuterRef("slug"),
function="ARRAY",
template="%(function)s[%(expressions)s]",
)
).values("id")
)
)
Run Code Online (Sandbox Code Playgroud)
或者,由于您只是检查一个值是否属于一个数组,我会ANY在 Postgres 中使用。为此,您可以定义自定义查找:
from django.db.models import Lookup
from django.db.models.fields import Field
class EqualAny(Lookup):
lookup_name = "any"
def as_sql(self, compiler, connection):
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params
# Notice I reversed right and left here for your example
return "%s = ANY (%s)" % (rhs, lhs), params
# We need to register the lookup here to make sure it happens during the app setup
Field.register_lookup(EqualAny)
Run Code Online (Sandbox Code Playgroud)
Purpose.objects.annotate(
conversation_count=SubqueryCount(
Conversation.objects.filter(goal_slugs__any=OuterRef("slug")).values("id")
)
)
Run Code Online (Sandbox Code Playgroud)
如果您提供模型,我可以检查生成的 SQL 以检查它是否有效
| 归档时间: |
|
| 查看次数: |
538 次 |
| 最近记录: |