Django在原始请求中选择相关

时间:2012-02-17 12:32:47

标签: django orm django-models

如何制作“手动”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相关模型已经被提取。

3 个答案:

答案 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