如何制作“手动”select_related模仿以避免不受欢迎的数据库命中?
我们有:
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 :(得分:10)
使用prefetch_related
的解决方案(这意味着将进行两次查询,cities
为1,countries
为1)取自{{ 3}}不是公共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'])
更新
现在在Django 1.10中django-users是公共API的一部分。
答案 1 :(得分: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
时,它将不会触发另一个数据库查询。
答案 2 :(得分: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