Django多对多交叉过滤

时间:2012-10-05 19:10:12

标签: python django orm django-queryset

为了简单起见,我假设我只有2个模型:Book,Author

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)

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

1 个答案:

答案 0 :(得分:8)

你可以&一堆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)

<强>更新

根据评论,我认为要求是让列表中至少有一位作者撰写的所有书籍,但排除列表外任何作者的书籍。

因此,我们构建一个查询集,选择我们讨厌的作者:

# 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)

这将给我们留下一个或多个好书所着的书籍!