Django: ManyToMany filtro corrispondente su TUTTI gli articoli in un elenco

Ho un modello del genere:

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

In breve:

Mi piacerebbe recuperare i libri i cui autori sono strettamente uguali a un determinato set di autori. Non sono sicuro che esista una singola query, ma qualsiasi suggerimento sarà utile.

In lungo:

Ecco cosa ho provato, (che non è riuscito a ottenere un 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 

… ed ecco cosa ho ottenuto:

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

In generale, come devo interrogare un modello con il vincolo che il suo campo ManyToMany contiene un insieme di oggetti dati come nel mio caso?

ps: ho trovato alcune domande SO pertinenti ma non ho potuto ottenere una risposta chiara. Qualsiasi buon puntatore sarà utile pure. Grazie.

Simile all’approccio di @ goliney, ho trovato una soluzione. Tuttavia, penso che l’efficienza potrebbe essere migliorata.

 # 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 

È ansible utilizzare ricerche complesse con oggetti 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) 

Ho incontrato lo stesso problema e sono giunto alla stessa conclusione di iuysal, fino a quando ho dovuto effettuare una ricerca di medie dimensioni (con 1000 record con 150 filtri la mia richiesta sarebbe scaduta).

Nel mio caso particolare, la ricerca non produrrebbe record poiché la possibilità che un singolo record si allinei a TUTTI i 150 filtri è molto rara, è ansible aggirare i problemi di prestazioni verificando che ci siano record nel QuerySet prima di applicare più filtri per salvare tempo.

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

Per qualche motivo Django applica i filtri per svuotare QuerySets. Ma se l’ottimizzazione deve essere applicata correttamente, tuttavia, è necessario utilizzare un QuerySet preparato e indici applicati correttamente.