2012-10-05 9 views
6

Aus Gründen der Einfachheit sagen wir, ich habe nur 2 Modelle: Buch, AutorDjango viele zu viele Kreuzung Filterung

class Author(models.Model): 
    name = models.CharField(max_length='100') 
    ... 

class Book(models.Model): 
    name = models.CharField(max_length='100') 
    authors = models.ManyToManyField(Author) 
    ... 

Ich möchte Bücher filtern, um eine Liste der Autoren verwenden. Was ich versuchte zu tun ist:

Aber hier, die Autoren werden ORed, wenn ich sie ANDed wollen. Gibt es eine Möglichkeit, UND viele-zu-viele Filterung?

Antwort

7

Sie könnten eine Reihe von Q-Objekte & zusammen:

q = Q() 
for author in authors: 
    q &= Q(authors=author) 
Books.objects.filter(q) 

Bücher ausgeschlossen werden, die Autoren außerhalb der Liste haben, können Sie die Abfrage, um Bücher mit genau der Anzahl der Autoren in der Liste einschränken:

Books.objects.annotate(count=Count('authors')).filter(count=len(authors)).filter(q) 

Update:

auf Kommentare Basierend denke ich, die Voraussetzung ist, t o alle Bücher, die von mindestens einem Autor in der Liste verfasst wurden, aber Bücher mit Autoren außerhalb der Liste ausschließen.

So bauen wir ein queryset die Autoren auswählen, die wir hassen:

# this queryset will be embedded as a subquery in the next 
bad_authors = Author.objects.exclude(name__in=['A1', 'A2']) 

ausschließen sie dann die Bücher, die wir wollen, finden:

# get all books without any of the bad_authors 
Books.objects.exclude(authors__in=bad_authors) 

Diese alle Bücher kehrt außer denen von jemandem verfasst außerhalb deiner Liste. Wenn Sie auch aufgeführt sind ohne Autoren ausschließen möchten, fügen Sie ein weiterer Anruf ausschließen:

Books.objects.exclude(authors__in=bad_authors).exclude(authors=None) 

Dies wird uns verlassen mit nur die von einem oder mehreren von den guten verfassten Bücher!

+0

Das ist großartig! Danke. –

+0

Noch etwas: Ich möchte in der Lage sein, Bücher zu filtern, die nur Autoren aus der Liste haben, keine zusätzlichen Autoren. Könntest du mir mit diesem Plz helfen? –

+0

@CodePirate: Ich habe die Antwort mit einem Beispiel aktualisiert. – dokkaebi