Django - 从子查询中注释多个字段

Django - Annotate multiple fields from a Subquery

我正在开发一个 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 上创建一个新的 subquery/subselect。我想在其 values() 参数上使用具有多个字段的相同 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

简而言之,整个问题是我有多个 "belongs" 到 A 的 B,所以我需要使用子查询来为 A.objects.all() 中的每个 A 选择一个特定的 B并将其附加到 A 上,使用 OuterRefs 和一些过滤器(我只想要 B 的几个字段),这对我来说是一个微不足道的问题。

提前感谢您的帮助!

我在这种情况下所做的就是使用 prefetch-related

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 个对象。