Django如何按关联对象的组合字段条件过滤查询集
原查询问题原因
你原来的写法出错的原因是Django处理同一个filter调用内的多个跨外键关系的过滤条件时,会为每个条件生成独立的JOIN语句,导致两个条件分别匹配不同的Book对象:只要图书馆下存在某本书标题符合要求,同时存在任意另一本书可借阅,就会被命中,完全不符合你的需求。
正确实现方案
方案1:先过滤符合条件的书籍再反向查询(逻辑最直观)
先筛选出同时满足标题和可借阅条件的书籍,再反向关联查询所属图书馆即可:
# 先过滤出所有符合要求的书 valid_books = Book.objects.filter(title="The Lord of the Rings", is_available=True) # 反向查询这些书所属的图书馆,去重避免重复结果 queryset = Library.objects.filter(sections__books__in=valid_books).distinct()
方案2:使用链式filter(写法最简洁)
Django的查询规则中,同一个filter内的多个跨关系参数对应独立JOIN,链式filter调用会复用之前的JOIN,拆分两个条件到链式的filter里即可让两个条件作用在同一本Book上:
queryset = Library.objects.filter( sections__books__title="The Lord of the Rings" ).filter( sections__books__is_available=True ).distinct()
方案3:使用Exists子查询(性能最优)
数据量较大时推荐用Exists子查询,不需要JOIN和去重,查询效率最高:
from django.db.models import Exists, OuterRef # 构造子查询:检查当前图书馆下是否存在符合条件的书 valid_book_subquery = Book.objects.filter( section__library=OuterRef('pk'), title="The Lord of the Rings", is_available=True ) queryset = Library.objects.filter(Exists(valid_book_subquery))
内容的提问来源于stack exchange,提问作者warpfactorten
相关产品推荐
相关产品推荐

