2010-06-04 16 views
28

Imagine el siguiente modelo:A left outer reverse select_related in Django?

class Parent(Model): 
    ... 

class Child(Model) 
    father = ForeignKey(Parent) 
    ... 

Algunos padres tienen hijos, otros no lo hacen (que no son los padres en el sentido real, es sólo un nombre ficticio).

me gustaría hacer la siguiente consulta: Quiero que todos los padres , y si tienen hijos, me traen los niños también. Ese sería el equivalente de una combinación externa izquierda a Mesa de niño, es decir:

select * from app_parent left join app_child on child_father_id=parent_id 

De esta manera, cuando invocan Parent.child_set en mi plantilla, no llegará a la base de datos de un millón de veces. ¿Hay una manera de hacer eso? Gracias

+1

Decidí que no debería usar este enfoque; realmente no hay soporte. Parecería que el mejor enfoque es seleccionar de la tabla más pequeña y luego, si es necesario, usar el templatetag "reagrupar" o la función set() en los campos principales, dependiendo del caso. –

+1

Una desventaja del enfoque de reagrupamiento es que no obtendrá Padres que no están allí – babonk

Respuesta

21

A partir de Django 1.4 prefetch_related hace lo que quiere.

Parent.objects.prefetch_related('child_set') 

Relacionados (!) Django docs: https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related.

+1

No creo que sea lo mismo que OP preguntó. Acabo de ejecutar select_prefetch y en realidad ejecuta 2 consultas: 1. seleccione * de los padres; 2. select * from child where parent_id IN (-bunch-of-comma-separated-ids-from-query-1-go-here-) ¿Es así como se supone que funciona o estoy haciendo algo mal? ? – gsharma

-7

creo que busca select_related()

+2

No del todo; en lo que a mí respecta, select_related() no realiza búsquedas inversas, solo mira hacia adelante. –

+0

¿Estás seguro de eso? Miré la documentación de Django y dice que sí para las relaciones 1: 1, pero no estoy seguro acerca de ForeignKey-relations ... –

+2

De acuerdo con los documentos select_related() puede hacer búsquedas inversas comenzando con Django 1.2, pero solo para OneToOneFields. –

13

este momento para publicar una vez más un enlace a mi blog, pero me han escrito sobre una técnica para simular select_related on backwards relationships.

+7

+1, pero un resumen aquí sería útil también. –

6

En este caso, creo que lo mejor que puede hacer es una lista de los niños, a continuación, obtener el padre de ellos, así:

children = Child.objects.filter(...).select_related('parent').order_by('parent') 

Luego, en la plantilla, utilice posiblemente un regroup (tenga en cuenta la order_by arriba):

{% regroup children by parent as parents %} 
<ul> 
{% for parent in parents %} 
    <li>{{ parent.grouper }} 
    <ul> 
    {% for child in parents.list %} 
    ... 
    {% endfor %} 
    </ul> 
    </li> 
{% endfor %} 
</ul> 
0

en django 1,3

Child.objects.select_related('father') 
#sql: select * from app_child left join app_parent on child_father_id=parent_id 
Cuestiones relacionadas