在Django中实现基于聚合维度的去重计数(附SQL示例)
Django按对象类型与动作类型统计对象数量的解决方案
方法一:纯ORM实现(推荐)
先聚合每个对象的event_type总和,再通过条件映射得到type_of_action,最后分组统计数量。
1. 聚合每个对象的event_type总和
首先按type_of_object和object_pk分组,计算每个对象的动作总和:
from django.db.models import Sum, Case, When, Value, CharField, Count # 聚合得到每个对象的动作总和 object_sums = Historique.objects.values( 'type_of_object', 'object_pk' ).annotate( sum_event_type=Sum('event_type') ).order_by() # 去掉默认排序,提升性能
2. 映射总和到type_of_action并统计数量
根据sum_event_type的取值定义映射规则,再按type_of_object和type_of_action分组统计对象数:
# 补充你的type_of_action映射逻辑,示例如下: stats = object_sums.annotate( type_of_action=Case( When(sum_event_type=2, then=Value('仅创建')), When(sum_event_type=3, then=Value('创建+修改')), When(sum_event_type=5, then=Value('创建+删除')), When(sum_event_type=7, then=Value('全操作')), When(sum_event_type=1, then=Value('仅修改')), When(sum_event_type=4, then=Value('仅删除')), When(sum_event_type=6, then=Value('修改+删除')), default=Value('未知'), output_field=CharField() ) ).values( 'type_of_object', 'type_of_action' ).annotate( object_count=Count('object_pk', distinct=True) ).order_by('type_of_object', 'type_of_action')
如果需要用整数表示type_of_action,只需把Value的字符串改成对应整数,同时把output_field改为IntegerField。
方法二:原生SQL复用
如果已有成熟的SQL查询,直接用RawQuerySet执行:
# 替换为你已有的SQL查询,示例如下 query = """ SELECT type_of_object, CASE WHEN SUM(event_type) = 2 THEN '仅创建' WHEN SUM(event_type) = 3 THEN '创建+修改' WHEN SUM(event_type) = 5 THEN '创建+删除' WHEN SUM(event_type) = 7 THEN '全操作' WHEN SUM(event_type) = 1 THEN '仅修改' WHEN SUM(event_type) = 4 THEN '仅删除' WHEN SUM(event_type) = 6 THEN '修改+删除' ELSE '未知' END AS type_of_action, COUNT(DISTINCT object_pk) AS object_count FROM historique GROUP BY type_of_object, type_of_action ORDER BY type_of_object, type_of_action """ stats = Historique.objects.raw(query)
注意事项
- 若
type_of_object允许为null,两种方法都会自动将null作为单独分组统计; - ORM方法兼容多数据库,原生SQL方法更适合复杂自定义逻辑。
内容的提问来源于stack exchange,提问作者gibbe75
相关产品推荐
相关产品推荐

