2012-02-17 77 views
12

如何使「手動」select_related模仿,以避免不必要的數據庫命中?Django選擇在原始請求相關

我們:

class Country: 
    name = CharField() 
class City: 
    country = models.ForeignKey(Country) 
    name = models.CharField() 

cities = City.objects.raw("select * from city inner join country on city.country_id = country.id where name = 'london'") 

#this will hill hit DB 
print cities[0].country.name 

如何告訴Django是相關的模型已經取出。

+0

你可以嘗試使用.values()來檢索城市作爲字典。請參閱:https://docs.djangoproject.com/en/dev/ref/models/querysets/#values – Jingo 2012-02-17 12:42:48

回答

1

我不確定你是否可以這樣做。或者,您可以從國家/地區表中選擇各個字段,並在每個實例上訪問它們。

cities = City.objects.raw("select city.*, name as country_name from city inner join country on city.country_id = country.id where name = 'london'") 

city = cities[0] 
# this will not hit the database again 
city.country_name 
+2

是的,這種方法可行,但需要進一步重新設計代碼。 – Andrew 2012-02-17 13:50:38

7

prefetch_related中的溶液(這指的是兩個查詢將被製成,1爲cities,1個用於countries)從django-users採取其不是公共API的一部分,在工作Django 1.7

from django.db.models.query import prefetch_related_objects 
#raw querysets do not have len() 
#thats why we need to evaluate them to list 
cities = list(City.objects.raw("select * from city inner join country on city.country_id = country.id where name = 'london'")) 
prefetch_related_objects(cities, ['country']) 

UPDATE

現在在Django 1.10 prefetch_related_objects是公共API的一部分。

6

不知道你是否仍然需要這個,但我從Alasdair的答案開始解決它。您想使用查詢中的信息來構建模型,或者當您嘗試訪問外鍵字段時,它仍然會觸發其他查詢。所以在你的情況下,你想要:

cities = list(City.objects.raw(""" 
     SELECT 
      city.*, country.name as countryName 
     FROM 
      cities INNER JOIN country ON city.country_id = country.id 
     WHERE 
      city.name = 'LONDON""")) 
    for city in cities: 
     city.country = Country(name=city.countryName) 

分配國家的行並沒有命中數據庫,它只是創建一個模型。之後,當您訪問city.country時,它不會觸發另一個數據庫查詢。