如何在Django中过滤同时关联多个指定ManyToMany对象的查询集?
多对多关联全量匹配的查询实现
该需求完全可以实现,借助Django ORM的内置能力就能完成,不需要手写原生SQL。
实现逻辑
我们要筛选的是「关联集合中同时包含所有指定SomeModel主键的OtherModel记录」,需要特别注意和“关联了任意一个目标主键的记录”做区分——后者是很多人查询时容易踩的误区。
写法1:链式逐次过滤(适合目标主键数量较少的场景)
逐一对每个目标主键添加关联过滤条件,通过连续的内连接逻辑,最终留存下满足所有关联要求的记录:
target_pks = [1, 10, 12, 20] query = OtherModel.objects.all() # 遍历目标主键依次叠加过滤条件 for pk in target_pks: query = query.filter(list_of_some_models__pk=pk) # 加distinct避免多对多关联产生的重复行问题 is_exist = query.distinct().exists()
写法2:聚合计数匹配(适合目标主键数量较多的场景)
通过注解统计每个OtherModel匹配到的目标主键数量,当匹配数等于目标列表总长度时,即为符合要求的记录。相比连续多次关联查询,长列表场景下这种写法的数据库查询性能更优:
from django.db.models import Count, Q target_pks = [1, 10, 12, 20] is_exist = OtherModel.objects.annotate( matched_pk_count=Count( 'list_of_some_models', filter=Q(list_of_some_models__pk__in=target_pks), distinct=True ) ).filter( matched_pk_count=len(target_pks) ).exists()
易错点提示
不要直接使用
filter(list_of_some_models__pk__in=target_pks)做判断
这种写法只会匹配「至少关联了任意一个目标主键的记录」,根本无法实现“同时关联所有目标主键”的匹配逻辑,和需求目标偏差极大。
如果后续需要匹配“关联集合恰好和目标列表完全一致、没有其他额外关联”的记录,只需要在上述过滤条件中,额外增加对OtherModel关联总数量的判断,确保关联总数和目标列表长度相等即可。
内容的提问来源于stack exchange,提问作者Akira Kotsugai
相关产品推荐
相关产品推荐

