如何用子查询为Django QuerySet注释关联ModelB的UID列表?
问题分析与解决方案
错误原因
你用Subquery时直接返回了多行field_1__uid结果,但Django的Subquery作为annotate的字段值时,要求子查询每行只能输出单个值,不能返回多行结果,所以触发more than one row returned by a subquery used as an expression错误。
正确实现方式
根据你的需求(获取符合user__id__in=user_ids条件的所有ModelA关联的ModelB的UID列表),分两种场景给出实现:
场景1:每个ModelA实例返回自身关联的ModelB的UID列表(仅筛选符合用户ID条件的ModelA)
如果只需要查询type="year"且用户在指定列表中的ModelA,并给每个实例添加自身关联的ModelB的UID列表:
from django.db.models import ArrayAgg user_ids = [1, 2, 3] result = ModelA.objects.filter( type="year", user__id__in=user_ids ).annotate( model_b_uids_list=ArrayAgg("field_1__uid", distinct=True) )
ArrayAgg会将当前ModelA关联的所有ModelB的UID聚合为一个数组;distinct=True避免重复的UID(如果同一个ModelB被关联多次)。
场景2:所有ModelA实例(仅筛选type="year")都返回符合用户ID条件的全局ModelB的UID列表
如果要给所有type="year"的ModelA实例,都添加所有符合user__id__in=user_ids的ModelA关联的ModelB的UID集合:
from django.db.models import ArrayAgg, Subquery user_ids = [1, 2, 3] # 先通过子查询聚合符合条件的所有UID agg_subquery = ModelA.objects.filter(user__id__in=user_ids).annotate( all_uids=ArrayAgg("field_1__uid", distinct=True) ).values("all_uids")[:1] # 限制返回单行 result = ModelA.objects.filter(type="year").annotate( model_b_uids_list=Subquery(agg_subquery) )
- 子查询里用
ArrayAgg将所有符合条件的UID聚合为一个数组,再通过[:1]确保返回单行; - 外层
Subquery就能正常将这个数组作为注释字段的值。
关于你尝试的ArrayAgg无效的可能原因
大概率是没有正确结合查询条件或聚合逻辑:
- 没有指定
distinct=True导致重复值干扰; - 子查询没有限制返回单行,依然返回多行结果;
- 没有正确关联外层查询或筛选条件。
内容的提问来源于stack exchange,提问作者Ankush Chavan
相关产品推荐
相关产品推荐

