我正在开发一个 Django 项目,其中我有一个“A”对象的查询集(
A.objects.all()
),并且我需要从“B”对象的子查询中注释多个字段。问题是,注释方法只能处理每个参数的一种字段类型(DecimalField、CharField 等),因此,为了注释多个字段,我必须使用类似的方法:
A.objects.all().annotate(b_id =Subquery(B_queryset.values('id')[:1],
b_name =Subquery(B_queryset.values('name')[:1],
b_other_field =Subquery(B_queryset.values('other_field')[:1],
... )
这是非常低效的,因为它在最终 SQL 上为我想要注释的每个字段创建一个新的子查询/子选择。我想在其 value() 参数上使用具有多个字段的相同 Subselect,并将它们全部注释在 A 的查询集上。我想用这样的东西:
b_subquery = Subquery(B_queryset.values('id', 'name', 'other_field', ...)[:1])
A.objects.all().annotate(b=b_subquery)
但是当我尝试这样做(并访问第一个元素
A.objects.all().annotate(b=b_subquery)[0]
)时,它会引发异常:
{FieldError}Expression contains mixed types. You must set output_field.
如果我设置
Subquery(B_quer...[:1], output_field=ForeignKey(B, models.DO_NOTHING))
,我会收到数据库异常:
{ProgrammingError}subquery must return only one column
简而言之,整个问题是我有多个“属于”A的B,所以我需要使用子查询,对于
A.objects.all()
中的每个A,选择一个特定的B并将其附加到该A上,使用OuterRefs 和一些过滤器(我只想要 B 的几个字段),这对我来说是一个微不足道的问题。
感谢您提前提供的任何帮助!
在这种情况下我所做的就是使用 prefetch-lated
a_qs = A.objects.all().prefetch_related(
models.Prefetch('b_set',
# NOTE: no need to filter with OuterRef (it wont work anyway)
# Django automatically filter and matches B objects to A
queryset=B_queryset,
to_attr='b_records'
)
)
现在
a.b_records
将是一个包含 a's
相关 b
对象的列表。根据您过滤 B_queryset
的方式,此列表可能仅限于 1 个对象。