Django对QuerySet追加filter后长度变大?多对多关联查询重复问题
问题原因
该现象是Django ORM处理多对多字段筛选的正常表现:
- 当你对多对多字段
match执行跨关联表的筛选时,ORM会自动将IdMatch表与多对多中间关联表做SQL JOIN操作 - 若单条
IdMatch记录关联了多条Match记录,JOIN后的结果集会为每一组关联关系生成独立的行,因此同一个IdMatch主键会重复出现。你调用count()时统计的是JOIN后的总行数,而非去重后的IdMatch对象数量,自然会出现筛选后计数反而大于初始计数的情况。
解决方案
有两种常用的实现方式可以避免主键重复:
- 直接调用
distinct()去重
这是适配你现有代码的最低修改成本方案,修改后代码如下:
idmatch = IdMatch.objects.filter(idsport=idsport) idmatchcount = idmatch.count() idmatch_liematch = idmatch.filter(match__isnull=False).distinct() count = idmatch_liematch.count()
distinct()会自动按IdMatch主键对结果去重,得到的就是无重复的符合条件的对象,计数也会恢复正常。
- 用
Exists子查询实现(更适合大数据量场景)
如果你的数据量级较大,JOIN后再去重的性能开销较高,可以用子查询的方式避免多表JOIN,天然不会产生重复记录:
from django.db.models import Exists, OuterRef idmatch = IdMatch.objects.filter(idsport=idsport) idmatchcount = idmatch.count() idmatch_liematch = idmatch.filter( Exists(Match.objects.filter(idmatch=OuterRef('pk'))) ) count = idmatch_liematch.count()
内容的提问来源于stack exchange,提问作者ThiMaul
相关产品推荐
相关产品推荐

