我有这样的书模型:
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问题,但无法得到明确的答案。任何好的指针也会有所帮助。感谢。答案 0 :(得分:16)
与@ 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
答案 1 :(得分:4)
您可以使用complex lookups with Q objects
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)
答案 2 :(得分:1)
Q()和Q()不等于.filter()。filter()。它们的原始SQL有所不同,通过将Q与&结合使用,其SQL仅添加了WHERE "book"."author" = "author_1" and "book"."author" = "author_2"
之类的条件。它应该返回空结果。
唯一的解决方案是通过链接过滤器以在同一表... 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")
上形成带有内部联接的SQL
答案 3 :(得分: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。 但是,如果要正确应用优化,则必须使用准备好的QuerySet并正确应用索引。