Django 多对多交集过滤

Posted

技术标签:

【中文标题】Django 多对多交集过滤【英文标题】:Django Many To Many intersection filtering 【发布时间】:2012-09-26 23:37:53 【问题描述】:

为了简单起见,假设我只有 2 个模型:书籍、作者

class Author(models.Model):
    name = models.CharField(max_length='100')
    ...

class Book(models.Model):
    name = models.CharField(max_length='100')
    authors = models.ManyToManyField(Author)
    ...

我想使用作者列表过滤图书。我试图做的是:

authors = [...] # a list of author objects
Books.objects.filter(authors__in=authors)

但是在这里,当我想要作者与作者时,他们会被 ORed。 有没有办法 AND 多对多过滤??

【问题讨论】:

【参考方案1】:

你可以将一堆 Q 对象 & 在一起:

q = Q()
for author in authors:
    q &= Q(authors=author)
Books.objects.filter(q)

要排除作者不在列表中的书籍,您可以将查询限制为与列表中作者数量完全相同的书籍:

Books.objects.annotate(count=Count('authors')).filter(count=len(authors)).filter(q)

更新:

基于 cmets,我认为要求是获取列表中至少一位作者撰写的所有书籍,但排除列表之外任何作者的书籍。

所以我们构建了一个查询集来选择我们讨厌的作者:

# this queryset will be embedded as a subquery in the next
bad_authors = Author.objects.exclude(name__in=['A1', 'A2'])

然后排除它们以找到我们想要的书籍:

# get all books without any of the bad_authors
Books.objects.exclude(authors__in=bad_authors)

这将返回所有书籍,但由您列表之外的人创作的书籍除外。如果您还想排除那些没有列出作者的人,请添加另一个排除调用:

Books.objects.exclude(authors__in=bad_authors).exclude(authors=None)

这将使我们只剩下一本或多本好书所写的书!

【讨论】:

还有一件事:我希望能够过滤仅包含列表中作者的书籍,没有额外的作者。你能帮我解决这个问题吗? @goliney 为什么这是错误的做法?请详细说明。 @dokkaebi 我又想了一遍,现在你的方法在我看来更正确。 +1 非常感谢@dokkaebi,太好了。但是我想我上一个问题有点不清楚,所以让我举个例子:authors = ['A1','A2'] @CodePirate 我认为与您的原始帖子相比,所有这些评论的变化是authors 实际上可能不是作者对象的列表。我发布的代码是否以某种方式失败?

以上是关于Django 多对多交集过滤的主要内容,如果未能解决你的问题,请参考以下文章

Django过滤器问题多对多

Django如何过滤多对多字段中的对象,而不是原始查询集

过滤后更新 Django 的多对多

Django 多对多字段过滤器列表

Django 多对多过滤器()

在Django中按关系字段过滤多对多关系