Django ORM在MySQL/MariaDB中按指定列分组的实现方法咨询
在Django ORM中实现无聚合的指定列分组(无需RawSQL)
不需要编写RawSQL,Django ORM提供了几种适配主流数据库(包括MySQL/MariaDB)的方案:
方法1:values() + distinct() 指定字段去重
普通distinct()会对全列去重,但结合values()限定需要分组的字段后,只会对指定字段组合去重,本质就是按指定列分组取唯一值,性能更优:
# 按id、username分组去重,返回字典格式结果 User.objects.filter(groups__name='foo').values('id', 'username').distinct()
方法2:annotate() 配合无意义聚合(获取完整模型实例)
如果需要返回完整的User模型实例而非字典,可以先通过annotate()添加一个不影响结果的聚合字段,再结合values()和distinct()筛选分组后的主键,最后通过主键查询获取实例:
from django.db.models import Count # 先获取分组后的主键集合 grouped_user_ids = User.objects.filter(groups__name='foo').annotate( dummy_count=Count('id') ).values('id').distinct() # 通过主键查询获取完整模型实例 unique_users = User.objects.filter(id__in=[item['id'] for item in grouped_user_ids])
方法3:子查询过滤(复杂关联场景)
针对多表关联的复杂分组需求,用子查询先筛选出符合条件的唯一主键,再外层查询获取实例:
from django.db.models import Subquery, OuterRef # 子查询获取符合条件的唯一user id subquery = User.objects.filter( id=OuterRef('id'), groups__name='foo' ).values('id').distinct() unique_users = User.objects.filter(id__in=Subquery(subquery))
优先级建议
优先使用values()+distinct()的组合,写法简洁且性能最优,适配所有主流数据库。
内容的提问来源于stack exchange,提问作者Rémi Desgrange
相关产品推荐
相关产品推荐

