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
相关产品推荐
相关产品推荐

