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 に答える
0

私は同じ問題に遭遇し、iuysal と同じ結論に達しましたが、中規模の検索を行う必要がありました (150 のフィルターを持つ 1000 のレコードで、私の要求はタイムアウトになります)。

私の特定のケースでは、単一のレコードが 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 に答える