2013-10-22 16 views
7

Czasami sensowne jest użycie select_related w szablonie django. Na przykład, że mam klasę rozciągający DetailViewdjango select_related w szablonie

class DemoCarView(DetailView): 
    model = Car 

opiera się na następujących contrived modelu

# Cars 
class Car(models.Model): 
    name = models.CharField(max_length=32) 

# Manufacturers 
class Manufacturer(models.Model): 
    name = models.CharField(max_length=32) 

# Parts 
class Part(models.Model): 
    name = models.CharField(max_length=32) 
    car = models.ForeignKey(Car) 
    manufacturer = models.ForeignKey(Manufacturer) 

Szablon HTML jest następnie

{{ car.name }} 
<ul> 
{% for part in car.part_set.all %} 
    <li>{{ part.name }} - {{ part.manufacturer.name }} </li> 
{% endfor %} 
</ul> 

Działa to doskonale, aby uzyskać samochód, części, które ją tworzą, oraz producentów tych części. Będzie to jednak wymagało użycia 2 + number_of_parts zapytań SQL. Łatwo naprawione w ten sposób:

{{ car.name }} 
<ul> 
{% for part in car.part_set.select_related.all %} 
    <li>{{ part.name }} - {{ part.manufacturer.name }} </li> 
{% endfor %} 
</ul> 

Teraz optymalizuje się 2 zapytania. Jednak select_related dołącza do Części z każdym kluczem obcym, który ma. Czy istnieje sposób, aby ograniczyć to do pożądanych powiązanych tabel. W Pythonie jest to po prostu:

Part.objects.select_related('manufacturer').filter(car=car) 

Czy można to zrobić w szablonie?

Uwaga: Wiem, że mogę to zrobić w widoku bardzo łatwo, zwracając kontekst dla "samochodu" i jednego dla "części" z select_related('manufacturer') na filtrze, ale jest to trochę więcej kodu w porównaniu do podobrazia DetailView klasa, której użyłem powyżej. Coś takiego:

class DemoCarViewPreload(TemplateView): 
    template_name = 'demo/car_detail_preload.html' 
    def get_context_data(self, **kwargs): 
     context = super(DemoCarViewPreload, self).get_context_data(**kwargs) 
     car = Car.objects.get(pk=kwargs.get('pk')) 
     context['car'] = car 
     context['parts'] = Part.objects.select_related('manufacturer').filter(car=car) 
     return context 

Wymaga to jednak szablon jest bardziej charakterystyczne dla tego widoku, jak to teraz trzeba korzystać z kontekstu „części” zamiast car.part_set.all. Co więcej, po prostu więcej pracy nad stworzeniem tego widoku.

Odpowiedz

18

Co powiesz na prostą metodę w modelu Car?

class Car(models.Model): 
    ... 
    def parts_with_manufacturers(self): 
     return self.part_set.select_related('manufacturer') 

a następnie

{% for part in car.parts_with_manufacturers %} 
    <li>{{ part.name }} - {{ part.manufacturer.name }} </li> 
{% endfor %} 
+0

To dobre rozwiązanie, nie można zrealizować w rzeczywistości metody dostępu w szablonie i part_set w modelu. Dzięki. – dpwrussell

Powiązane problemy