2011-03-25 29 views
39

tengo el siguiente modelo de Django:Django queryset con la filtración en el reverso clave externa

class Make: 
    name = models.CharField(max_length=200) 

class MakeContent: 
    make = models.ForeignKey(Make) 
    published = models.BooleanField() 

Me gustaría saber si es posible (sin escribir SQL directamente) para mí para generar un conjunto de consultas que contiene toda Make s y cada uno relacionado MakeContent s donde published = True.

+0

¿Podría ser más específico acerca de su pregunta? – pyeleven

Respuesta

9

Django no es compatible con el método select_related() para búsquedas inversas de claves externas, por lo que lo mejor que puede hacer sin salir de Python son dos consultas a la base de datos. La primera es tomar todas las Marcas que contienen MakeContents donde publicado = True, y la segunda es tomar todas las MakeContents donde publicado = True. Luego tiene que recorrer y ordenar los datos como lo desee. He aquí un buen artículo sobre cómo hacer esto:

http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/

+18

No creo que deba responder a esta pregunta ahora ... –

+2

vea el método prefetch_related() para que simplifique las dos consultas que menciona. –

42

Sí, yo creo que usted quiere

make = Make.objects.get(pk=1) 
make.make_content_set.filter(published=True) 

o tal vez

make_ids = MakeContent.objects.filter(published=True).values_list('make_id', flat=True) 
makes = Make.objects.filter(id__in=make_ids) 
+3

'.values' debe reemplazarse por' .values_list' si no me equivoco. – exfizik

+1

Su primer fragmento de código no funciona. Obtiene todos los MakeContents para * one * make, donde se necesita MakeContents para todas las marcas. _set funciona para un solo objeto pero no para un conjunto de consulta. – knite

+0

¿Cuál es el punto de agregar 'flat = True'? Los identificadores ya serán únicos por definición, y garantizar nuevamente que sean únicos podría requerir un cálculo adicional. – pintoch

9

Vamos a traducir respuesta redactada de Spike en códigos de espectadores futuros. Tenga en cuenta que cada 'Make' puede tener cero a múltiples 'MakeContent'

Si el autor de la pregunta significa para consultar 'Hacer' con POR LO MENOS UN 'MakeContent' cuya publicada = True, segundo fragmento de Jason Christa responde a la pregunta .

El fragmento es equivalente a

makes = Make.objects.select_related().filter(makecontent__published=True).distinct() 

Pero si el autor de la pregunta significa para consultar 'hacer' con TODO 'MakeContent' cuya publicada = True, siguiendo el 'hace' más arriba,

import operator 
make_ids = [m.id for m in makes if 
    reduce(operator.and_, [c.published for c in m.makecontent_set.all()]) 
] 
makes_query = Make.objects.filter(id__in=make_ids) 

contiene la consulta deseada.

4

Sé que esta es una pregunta muy antigua, pero estoy respondiendo. Como creo que mi respuesta puede ayudar a otros. He cambiado un poco el modelo de la siguiente manera. He usado Django 1.8.

class Make(models.Model): 
    name = models.CharField(max_length=200) 

class MakeContent(models.Model): 
     make = models.ForeignKey(Make, related_name='makecontent') 
     published = models.BooleanField() 

He utilizado el siguiente queryset.

Make.objects.filter(makecontent__published=True) 

Espero que ayude.

Cuestiones relacionadas