2012-10-05 34 views
6

En aras de la simplicidad vamos a decir que sólo tengo 2 modelos: libro, autorDjango muchos a muchos intersección filtrado

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

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

que desea filtrar Libros a través de una lista de autores. Lo que traté de hacer es:

authors = [...] # a list of author objects 
Books.objects.filter(authors__in=authors) 

Pero aquí, los autores estarán ORed cuando los quiera ANDed. ¿Hay alguna manera de filtrar AND de muchos a muchos?

Respuesta

7

Se podría & juntos un montón de objetos Q:

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

Para excluir libros que tienen autores fuera de la lista, que podría limitar la consulta a los libros con exactitud el número de autores en la lista:

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

actualización:

Basándose en los comentarios, creo que el requisito es t o obtener todos los libros escritos por al menos un autor en la lista, pero excluir libros con autores que estén fuera de la lista.

Así se construye un conjunto de consultas seleccionando los autores que odiamos:

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

Entonces excluirlos de encontrar los libros que queremos:

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

Esto devolverá todos los libros excepto aquellos escrito por alguien fuera de tu lista. Si también desea excluir los que no tienen autores mencionados, añadir otro excluyen llamada:

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

Esto nos deja con sólo los libros escritos por uno o más de los buenos!

+0

¡Eso es increíble! Gracias. –

+0

Una cosa más: quiero poder filtrar libros que solo tengan autores de la lista, sin autores adicionales. ¿Podrías ayudarme con eso? –

+0

@ CodePirate: He actualizado la respuesta con un ejemplo. – dokkaebi

Cuestiones relacionadas