22

我有这样一个 Book 模型:

class Book(models.Model):
    authors = models.ManyToManyField(Author, ...)
    ...

简而言之:

我想检索其作者严格等于给定作者集的书籍。我不确定是否有一个查询可以做到这一点,但任何建议都会有所帮助。

长篇:

这是我尝试过的,(未能运行获取 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

...这就是我得到的:

AttributeError: 'NoneType' object has no attribute '_meta'

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

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

4

4 回答 4

18

与@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
于 2012-11-07T17:34:48.957 回答
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)
于 2012-11-07T13:27:12.710 回答
2

Q() & Q() 不等于 .filter().filter()。他们的原始 SQL 不同,其中使用 Q 和 &,它的 SQL 只是添加一个条件,如 WHERE "book"."author" = "author_1" and "book"."author" = "author_2". 它应该返回空结果。

The only solution is just by chaining filter to form a SQL with inner join on same table: ... ON ("author"."id" = "author_book"."author_id") INNER JOIN "author_book" T4 ON ("author"."id" = T4."author_id") WHERE ("author_book"."author_id" = "author_1" AND T4."author_id" = "author_1")

于 2019-01-08T21:51:59.503 回答
0

我遇到了同样的问题并得出了与 iuysal 相同的结论,直到我不得不进行中型搜索(有 1000 条记录和 150 个过滤器,我的请求会超时)。

在我的特殊情况下,搜索将导致没有记录,因为单个记录与所有 150 个过滤器对齐的机会非常罕见,您可以通过在应用更多过滤器之前验证 QuerySet 中有记录来解决性能问题以保存时间。

# 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:
   if candidate_books.count() > 0:
      candidate_books = candidate_books.filter(authors=author)

出于某种原因,Django 将过滤器应用于空查询集。但是,如果要正确应用优化,则需要使用准备好的 QuerySet 和正确应用的索引。

于 2016-12-08T08:41:49.383 回答