9

簡単にするために、モデルが本と著者の 2 つしかないとします。

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 で結合したいときに OR で結合します。AND多対多フィルタリングする方法はありますか??

4

1 に答える 1

15

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)

アップデート:

コメントに基づいて、リスト内の少なくとも 1 人の著者によって作成されたすべての本を取得する必要があると思いますが、リスト外の著者の本は除外します。

そこで、嫌いな著者を選択するクエリセットを作成します。

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

これにより、1 人または複数の優れた人によって書かれた本だけが残ります。

于 2012-10-05T19:44:34.063 に答える