9

django テンプレートで select_related を使用することが理にかなっている場合があります。たとえば、DetailView を拡張するクラスがあるとします。

class DemoCarView(DetailView):
    model = Car

以下の考案されたモデルに基づく

# 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)

html テンプレートは次のようになります。

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

これは、車、それを構成する部品、およびそれらの部品のメーカーを取得するのに最適です。ただし、これには 2+number_of_parts SQL クエリが使用されます。次のように簡単に修正できます。

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

これで、最適な 2 つのクエリが実行されます。ただし、select_relatedそれが持っているすべての外部キーでパーツを結合しています。これを目的の関連テーブルのみに制限する方法はありますか。Python では次のようになります。

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

これはテンプレートで実行できますか?

注: 'car' のコンテキストと 'parts' のコンテキストをselect_related('manufacturer')フィルターで返すことにより、ビューでこれを非常に簡単に実行できることはわかっていますが、使用した DetailView サブクラスに比べてコードがかなり多くなります。その上。このようなもの:

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

ただし、テンプレートは、car.part_set.all. また、そもそもこのビューを作成するのは単純に手間がかかります。

4

1 に答える 1

24

Carモデルの簡単な方法はどうですか?

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

その後

{% for part in car.parts_with_manufacturers %}
    <li>{{ part.name }} - {{ part.manufacturer.name }} </li>
{% endfor %}
于 2013-10-22T16:55:23.813 に答える