Подтвердить что ты не робот

Выбор Django в необработанном запросе

Как сделать "ручную" 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, что связанные модели уже получены.

4b9b3361

Ответ 1

Решение с 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'])

ОБНОВЛЕНИЕ

Теперь в Django 1.10 prefetch_related_objects является частью общедоступного API.

Ответ 2

Не уверен, что вам все еще нужно это, но я решил это, начиная с ответа Аласдайра. Вы хотите использовать информацию из запроса для сборки модели, иначе она будет запускать дополнительные запросы при попытке получить доступ к полю внешнего ключа. Поэтому в вашем случае вам нужно:

    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 он не будет запускать другой запрос базы данных.

Ответ 3

Я не уверен, сможешь ли ты это сделать. В качестве альтернативы вы можете выбрать отдельные поля из таблицы страны и получить к ним доступ в каждом экземпляре.

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