2011-07-08 74 views
2

例如,我有這樣的機型:Django的 - 反向查找

class Person(models.Model): 
    name = models.CharField(max_length=20) 
    employer = models.CharField(max_length=20) 

class Car(models.Model): 
    person = models.ForeignKey(Person) 
    name = models.CharField(max_length=10) 
    model = models.CharField(max_length=10) 
    ... 

嗯,我想所有的人如何擁有一些特定的汽車:

people = Person.objects.filter(car__name="Toyota") 

現在我想寫這個人與他的車的細節。我可以這樣做:

for person in people: 
    ... 
    cars = person.car_set.filter(name="Toyota") 
    ... 

但它是數據庫的下一個命中。我怎樣才能避免這種情況?有什麼辦法可以簡化嗎?

回答

3

首先選擇數據汽車及相關人當車名

cars = Car.objects.select_related("person").filter(name="Toyota").order_by("person") 

現在你把所有的名字是豐田汽車與人對於汽車,ordered_by人沿着汽車。

現在使用Python itertools.groupby到這組列表中爲每個人

from itertools import groupby 
for k, g in groupby(cars, lambda x: x.person): 
     person = k 
     cars = list(g) 

現在在迭代你的人,他的車(他的名字是「豐田」)。 您會注意到只有單個查詢發生,然後對緩存的信息執行以下操作。

+0

使用這種技術的一個副作用是,如果你有沒有汽車的人,你不會在那個查詢中看到。這是因爲查詢是通過汽車領域啓動的。 – arustgi

0

退房select_related(),我用它之前,請務必跨越多個模型爲一個大的查詢很多小查詢:https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related

它通過預填充QuerySet,所以你要car_set訪問將已經那裏並不會導致新的查詢。

+0

即使我需要再次過濾嗎?我不想要每輛車,但只有豐田。 – yetty

+0

如果你重複使用同一個'QuerySet',它可能會工作。查閱:https://docs.djangoproject.com/en/dev/topics/db/queries/#caching-and-querysets瞭解更多有關'QuerySet'緩存的細節。 – kcbanner

0

我不認爲有避免額外的數據庫命中。如果你擔心拍過多的查詢,你可以嘗試這樣的事:

from collections import defaultdict 

cars = Car.objects.filter(**kwargs).selected_related('person') 
owners = defaultdict(list) 

for car in cars: 
    owners[car.person].append(car) 

這應該只是一個查詢選擇所有相關的汽車以及他們相關的人