简体   繁体   English

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

[英]Django - Annotate multiple fields from a Subquery

I'm working on a Django project on which i have a queryset of a 'A' objects ( A.objects.all() ), and i need to annotate multiple fields from a 'B' objects' Subquery.我正在处理一个 Django 项目,在该项目上我有一个“A”对象( A.objects.all() )的查询集,我需要从“B”对象的子查询中注释多个字段。 The problem is that the annotate method can only deal with one field type per parameter (DecimalField, CharField, etc.), so, in order to annotate multiple fields, i must use something like:问题是 annotate 方法只能处理每个参数的一种字段类型(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],
                         ... )

Which is very inefficient, as it creates a new subquery/subselect on the final SQL for each field i want to annotate.这是非常低效的,因为它为我要注释的每个字段在最终 SQL 上创建了一个新的子查询/子选择。 I would like to use the same Subselect with multiple fields on it's values() params, and annotate them all on A's queryset.我想在它的 values() 参数上使用具有多个字段的相同子选择,并将它们全部注释在 A 的查询集上。 I'd like to use something like this:我想使用这样的东西:

b_subquery = Subquery(B_queryset.values('id', 'name', 'other_field', ...)[:1])
A.objects.all().annotate(b=b_subquery)

But when i try to do that (and access the first element A.objects.all().annotate(b=b_subquery)[0] ) it raises an exception:但是当我尝试这样做(并访问第一个元素A.objects.all().annotate(b=b_subquery)[0] )时,它引发了一个异常:

{FieldError}Expression contains mixed types. You must set output_field.

And if i set Subquery(B_quer...[:1], output_field=ForeignKey(B, models.DO_NOTHING)) , i get a DB exception:如果我设置Subquery(B_quer...[:1], output_field=ForeignKey(B, models.DO_NOTHING)) ,我会得到一个数据库异常:

{ProgrammingError}subquery must return only one column

In a nutshell, the whole problem is that i have multiple Bs that "belongs" to a A, so i need to use Subquery to, for every A in A.objects.all() , pick a specific B and attach it on that A, using OuterRefs and a few filters (i only want a few fields of B), which seens a trivial problem for me.简而言之,整个问题是我有多个“属于”A 的 B,所以我需要使用子查询,对于A.objects.all()每个 A,选择一个特定的 B 并将其附加到A,使用 OuterRefs 和一些过滤器(我只想要 B 的几个字段),这对我来说是一个微不足道的问题。

Thanks for any help in advance!提前感谢您的任何帮助!

What I do in such situations is to use 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'
    )
)

Now a.b_records will be a list containing a's related b objects.现在a.b_records将是一个包含a's相关b对象的列表。 Depending on how you filter your B_queryset this list may be limited to only 1 object.根据您过滤B_queryset此列表可能仅限于 1 个对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM