Django子查询返回8列期望1列OperationalError报错解决
错误触发原因
报错核心是Subquery用法不符合SQL子查询的语法规则:
- Django中
Subquery生成的数据库子查询必须仅返回单个字段结果,你传入的questions_with_tag查询集没有指定返回字段,默认会查询Question模型继承自Post、自身定义的全部共8个字段,和数据库要求的单返回值规则冲突,因此抛出sub-select returns 8 columns - expected 1错误。 - 额外逻辑问题:在
Count中嵌套Subquery属于冗余写法,通过关联表聚合就可以直接实现统计需求,不需要额外构造子查询。
正确修改方案
不需要使用Subquery,直接通过多对多关联关系做聚合即可,注意加distinct=True避免多对多连表时的重复计数问题,修改后的get_tag_post_data方法如下:
from django.db.models import Count, Q class Profile(Model): user = OneToOneField(settings.AUTH_USER_MODEL, on_delete=CASCADE) def get_tag_post_data(self): return Tag.objects.filter( question__profile=self ).annotate( # 统计当前标签关联的、属于当前用户的问题数量,去重避免计数错误 count=Count('question', filter=Q(question__profile=self), distinct=True) )
修改后返回的QuerySet会包含该用户所有问题关联的3个标签,每个标签的count注解值对应该用户使用该标签的问题数:TagA为1、TagB为1、TagZ为2,可以通过现有单元测试。
如果你一定要保留Subquery写法(不推荐,性能更差且逻辑冗余),需要强制子查询只返回单个字段,同时清除默认排序避免额外字段被带入查询:
from django.db.models import OuterRef, Subquery, Count def get_tag_post_data(self): questions_with_tag = self.questions.filter( tags__name=OuterRef("name") ).values("id").order_by() # 仅返回id单列,清除默认排序 return Tag.objects.filter( question__profile=self ).annotate(count=Count(Subquery(questions_with_tag))).distinct()
内容的提问来源于stack exchange,提问作者binny
相关产品推荐
相关产品推荐

