Django:ManyToMany过滤器匹配列表中的所有项目

iuy*_*sal 18 django django-orm manytomanyfield django-queryset

我有这样的书模型:

class Book(models.Model):
    authors = models.ManyToManyField(Author, ...)
    ...
Run Code Online (Sandbox Code Playgroud)

简而言之:

我想检索作者严格等于给定作者集的书籍.我不确定是否有单个查询可以执行此操作,但任何建议都会有所帮助.

长期:

这是我尝试过的(无法运行获取AttributeError)

# A sample set of authors
target_authors = set((author_1, author_2))

# To reduce the search space, 
# first retrieve those books with just 2 authors.
candidate_books = Book.objects.annotate(c=Count('authors')).filter(c=len(target_authors))

final_books = QuerySet()
for author in target_authors:
    temp_books = candidate_books.filter(authors__in=[author])
    final_books = final_books and temp_books
Run Code Online (Sandbox Code Playgroud)

......这就是我得到的:

AttributeError: 'NoneType' object has no attribute '_meta'
Run Code Online (Sandbox Code Playgroud)

一般来说,我应该如何查询模型,其约束条件是其ManyToMany字段包含一组给定的对象,就像我的情况一样?

ps:我发现了一些相关的SO问题,但无法得到明确的答案.任何好的指针也会有所帮助.谢谢.

iuy*_*sal 15

与@ goliney的方法类似,我找到了一个解决方案.但是,我认为效率可以提高.

# A sample set of authors
target_authors = set((author_1, author_2))

# To reduce the search space, first retrieve those books with just 2 authors.
candidate_books = Book.objects.annotate(c=Count('authors')).filter(c=len(target_authors))

# In each iteration, we filter out those books which don't contain one of the 
# required authors - the instance on the iteration.
for author in target_authors:
    candidate_books = candidate_books.filter(authors=author)

final_books = candidate_books
Run Code Online (Sandbox Code Playgroud)


Ser*_*ney 5

您可以对 Q 对象使用复杂的查找

from django.db.models import Q
...
target_authors = set((author_1, author_2))
q = Q()
for author in target_authors:
    q &= Q(authors=author)
Books.objects.annotate(c=Count('authors')).filter(c=len(target_authors)).filter(q)
Run Code Online (Sandbox Code Playgroud)

  • 谢谢@goliney,虽然这种方法简洁且鼓舞人心,但我想它并没有做我想要的。如果只有一个作者,它工作正常,但是当有多个作者时,AND 过程可能会导致不可能的约束,例如(其中 a=x AND a=y)。 (5认同)
  • 事实证明,Q() 行为对我来说有些不清楚。根据 [this relative question](http://stackoverflow.com/a/5542966/1065780) 我在 SO 上发现,`Q() & Q()` 不等于 `.filter().filter()` . 谢谢你的问题 (4认同)
  • 感谢您的链接并分享您的时间。 (2认同)