如何在Django QuerySet中实现类似Pandas的GroupBy分组统计?
解决Django QuerySet分组聚合的需求
没问题,我来帮你搞定这个需求!首先得明确你要的是按type_id(或者说对应的col2,因为你数据里同一个type_id的col2是一致的)分组,计算col1的总和,同时关联type_id对应的名称。下面是具体的实现步骤:
第一步:确认模型结构
假设你的Django模型是这样定义的(如果和你的实际模型有出入,调整字段名即可):
from django.db import models class Type(models.Model): name = models.CharField(max_length=100) # 其他字段... class YourModel(models.Model): type = models.ForeignKey(Type, on_delete=models.CASCADE, db_column='type_id', related_name='related_items') col1 = models.IntegerField() col2 = models.CharField(max_length=10) col3 = models.CharField(max_length=10)
第二步:编写QuerySet
要得到你想要的结果,我们需要用values()指定分组字段,再用annotate()做聚合计算,最后用F()表达式关联关联模型的字段:
from django.db.models import Sum, F # 构建QuerySet queryset = YourModel.objects.values( 'type_id', 'col2' # 按这两个字段分组(因为同一type_id的col2一致,不会拆分分组) ).annotate( id=F('type_id'), # 把type_id重命名为结果里的'id' count_col1=Sum('col1'), # 计算每组col1的总和(对应你要的count_col1) type_id__name=F('type__name') # 关联Type模型的name字段 ).values( 'id', 'count_col1', 'type_id__name', 'col2' # 指定最终输出的字段顺序和名称 ).order_by('id') # 按id排序,确保结果顺序和示例一致 # 转换成字典列表 result = list(queryset)
第三步:结果验证
执行上面的代码后,result就会和你需要的结构完全一致:
[ {'id':1, 'count_col1': 5, 'type_id__name':'balh', 'col2':'b'}, {'id':2, 'count_col1':3, 'type_id__name': 'balab', 'col2':'a'} ]
关键知识点解释
values():先指定分组的字段,Django会自动按这些字段进行分组。annotate():对每个分组执行聚合操作,这里用Sum计算col1的总和(注意你示例里的count_col1其实是总和,不是计数,如果是计数的话用Count)。F()表达式:用来直接引用数据库中的字段值,避免额外的查询开销,这里用来关联Type模型的name字段,以及把type_id重命名为id。
如果你的数据中存在同一个type_id对应不同col2的情况,你可以用Max('col2')或Min('col2')来固定取某一个值,比如:
from django.db.models import Sum, F, Max queryset = YourModel.objects.values( 'type_id' ).annotate( id=F('type_id'), count_col1=Sum('col1'), type_id__name=F('type__name'), col2=Max('col2') # 取每组col2的最大值,保证每个分组只有一个col2值 ).values( 'id', 'count_col1', 'type_id__name', 'col2' ).order_by('id')
内容的提问来源于stack exchange,提问作者MHB
相关产品推荐
相关产品推荐

