2010-06-04 14 views
28

Wyobraźmy sobie następujący model:Lewa zewnętrzna ścieżka zwrotna select_related w Django?

class Parent(Model): 
    ... 

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

Niektórzy rodzice mają dzieci, inne nie (nie są rodzice w prawdziwym znaczeniu, to tylko fikcyjna nazwa).

Chciałbym wprowadzić następujące zapytanie: Chcę listy wszystkich rodziców,, a jeśli mają dzieci, mi przynieść dzieciom zbyt. To byłoby równoznaczne z lewego sprzężenia zewnętrznego do tabeli podrzędnej, czyli:

select * from app_parent left join app_child on child_father_id=parent_id 

ten sposób, gdy przywołuję Parent.child_set w moim szablonu, nie trafi baza danych gazillion razy. Czy jest jakiś sposób na zrobienie tego? Dzięki

+1

Uznałem, że nie powinienem stosować tego podejścia; naprawdę nie ma wsparcia. Wydaje się, że najlepszym sposobem jest wybranie z najbardziej dziecinnej tabeli, a następnie, w razie potrzeby, użycie funkcji "przegrupuj" templatetag lub funkcji set() w polach macierzystych, w zależności od przypadku. –

+1

Wadą podejścia przegrupowania jest to, że nie dostanie Rodziców, których tam nie ma – babonk

Odpowiedz

21

Zaczynając od Django 1.4 prefetch_related robi to, co chcesz.

Parent.objects.prefetch_related('child_set') 

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

+1

Nie sądzę, że jest to to samo co OP. Właśnie uruchomiłem select_prefetch i to faktycznie uruchamia 2 zapytania: 1. wybierz * od rodziców; 2. wybierz * z podrzędnego, gdzie parent_id IN (-bunch-of-comma-separated-ids-from-query-1-go-here-) Czy to ma działać lub czy robię coś złego ? – gsharma

-7

myślę szukasz select_related()

+2

Niezupełnie; O ile mi wiadomo, select_related() nie ma odwrotnego wyszukiwania, to tylko oczekuje. –

+0

Jesteś tego pewien? Spojrzałem na dokumentację Django i napisałem, że robi to dla relacji 1: 1, ale nie jestem pewien co do stosunków ForeignKey ... –

+2

Według dokumentów select_related() może wykonywać wyszukiwania odwrotne zaczynając od Django 1.2, ale tylko dla OneToOneFields. –

6

W tym przypadku, myślę, że najlepiej zrobić to wymienić dzieci, a następnie dostać się rodzica z nich, podobnie jak to:

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

Następnie w szablonie, ewentualnie użyć regroup (uwaga order_by powyżej)

{% 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

w django 1,3

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