You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django拼接QuerySet后按annotate生成的grupo字段排序报错

解决QuerySet拼接后排序的报错问题

问题场景

从asiento表生成三个QuerySet,通过annotate截取cuenta__codigo的不同长度生成grupo字段,并聚合sum_debe和sum_haber:

lista1 = asiento.objects.all().annotate(grupo=Substr("cuenta__codigo",1,1)).values('grupo').annotate(sum_debe=Sum("debe"),sum_haber=Sum("haber"))
lista2 = asiento.objects.all().annotate(grupo = Substr("cuenta__codigo",1,3)).values('grupo').annotate(sum_debe=Sum("debe"),sum_haber=Sum("haber"))
lista3 = asiento.objects.all().annotate(grupo = Substr("cuenta__codigo",1,6)).values('grupo').annotate(sum_debe=Sum("debe"),sum_haber=Sum("haber"))

用chain拼接三个QuerySet后得到字典格式的结果:

listan = chain(lista1,lista2,lista3)

示例结果:

{'grupo': '1', 'sum_debe': Decimal('251.680000000000'), 'sum_haber': Decimal('0')}
{'grupo': '2', 'sum_debe': Decimal('0'), 'sum_haber': Decimal('251.680000000000')}

尝试用attrgetter按grupo排序时出现报错:

listan = sorted(chain(lista1,lista2,lista3),key=attrgetter('grupo'))

错误信息:

'dict' object has no attribute 'grupo'

解决方法

报错原因是values()返回的是字典对象,而非模型实例,attrgetter通过属性访问的方式取值,无法识别字典的键。可以用以下两种方式解决:

方法1:使用lambda表达式作为排序key

直接通过字典键访问的方式获取grupo值:

listan = sorted(chain(lista1, lista2, lista3), key=lambda x: x['grupo'])

方法2:使用itemgetter替代attrgetter

itemgetter专门用于获取可迭代对象(如字典)的元素,先导入模块再使用:

from operator import itemgetter

listan = sorted(chain(lista1, lista2, lista3), key=itemgetter('grupo'))

补充说明

如果不需要字典格式,也可以去掉values('grupo'),保留模型实例的annotate结果,这样后续可以继续用attrgetter排序,但会返回完整的模型对象,数据量较大时需权衡使用。

内容的提问来源于stack exchange,提问作者Rene

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:45:23