Django多对多关联查询:筛选符合条件的未隐藏书籍
问题:筛选符合条件的书籍记录
需要筛选出满足以下条件的书籍:
- 书籍自身
is_hidden为False - 所有关联的作者、译者、分类的
is_hidden均为False
数据量可达8万条,希望避免循环实现,求正确的查询方法。
模型定义
class Category(CustomModel): name = models.CharField(max_length=32, unique=True, null=False, blank=False) ... is_hidden = models.BooleanField(default=False) class Person(CustomModel): first_name = models.CharField(max_length=64, null=False, blank=False) ... is_hidden = models.BooleanField(default=False) class Book(CustomModel): title = models.CharField(max_length=128, null=False, blank=False) authors = models.ManyToManyField(Person, null=False, blank=False) translators = models.ManyToManyField(Person, null=True, blank=True) ... categories = models.ManyToManyField(Category, null=False, blank=False) ... is_hidden = models.BooleanField(default=False)
尝试过的查询
第一种:
books = Book.objects.filter( is_hidden=False, authors__is_hidden=False, translators__is_hidden=False, categories__is_hidden=False).distinct()
第二种:
books = Book.objects.filter( is_hidden=False, authors__is_hidden__in=[False], translators__is_hidden__in=[False], categories__is_hidden__in=[False]).distinct()
解决方案
之前的查询逻辑有误:filter的正向多对多关联条件只会筛选出存在至少一个符合条件的关联对象的书籍,但无法保证所有关联对象都满足is_hidden=False。正确思路是用exclude排除掉存在隐藏关联对象的书籍,再结合自身条件。
注意translators字段允许为空:如果书籍有译者,则所有译者都不能隐藏;如果没有译者,不影响筛选。
最终查询代码:
books = Book.objects.filter(is_hidden=False)\ .exclude(authors__is_hidden=True)\ .exclude(categories__is_hidden=True)\ .exclude(translators__is_hidden=True)
逻辑说明
- 先筛选自身未隐藏的书籍:
filter(is_hidden=False) - 排除存在隐藏作者的书籍:只要有一个作者隐藏,就排除该书
- 排除存在隐藏分类的书籍:只要有一个分类隐藏,就排除该书
- 排除存在隐藏译者的书籍:有译者且其中存在隐藏项时排除,无译者的书籍不受此条件影响
这种方式是数据库层面的查询,无需循环处理,效率适配大数据量场景,通常也不需要额外加distinct()(除非模型存在其他重复数据情况)。
内容的提问来源于stack exchange,提问作者niaei
相关产品推荐
相关产品推荐

