Множество запросов из полей Django Foreignkey - PullRequest
5 голосов
/ 11 июля 2009

Я весь день пускал слюни из-за Django, кодируя внутренний сайт в рекордно короткие сроки, но теперь я замечаю, что что-то очень неэффективно с моими ForeignKeys в модели.

У меня есть модель, которая имеет 6 ForeignKeys, которые в основном являются таблицами поиска. Когда я запрашиваю все объекты и отображаю их в шаблоне, он выполняет около 10 запросов на элемент. Вот некоторый код, который должен объяснить это лучше:

class Website(models.Model):
    domain_name = models.CharField(max_length=100)
    registrant = models.ForeignKey('Registrant')
    account = models.ForeignKey('Account')
    registrar = models.ForeignKey('Registrar')
    server = models.ForeignKey('Server', related_name='server')
    host = models.ForeignKey('Host')
    target_server = models.ForeignKey('Server', related_name='target')

class Registrant(models.Model):
    name = models.CharField(max_length=100)

... и еще 5 простых таблиц. На сайте 155 записей, и в представлении, которое я использую:

Website.objects.all()

В итоге выполняется 1544 запроса. В шаблоне я использую все внешние поля, как в:

<span class="value">Registrant:</span> <a href="/filter/registrant/{{ website.registrant.id }}">{{ website.registrant.name }}</a><br />

Так что я знаю, что будет выполняться много запросов ... но кажется, что это чрезмерно. Это нормально? Разве я не должен делать это таким образом?

Я довольно новичок в Django, так что, надеюсь, я просто делаю что-то глупое. Это определенно довольно удивительный фреймворк.

1 Ответ

5 голосов
/ 11 июля 2009

Вы должны использовать функцию select_related , например,

Website.objects.select_related()

, чтобы он автоматически выполнял объединение и следил за всеми этими внешними ключами при выполнении запроса, а не загружал их по требованию по мере их использования. Django загружает данные из базы данных лениво, поэтому по умолчанию вы получаете следующее поведение

# one database query
website = Website.objects.get(id=123)

# first time account is referenced, so another query
print website.account.username 

# account has already been loaded, so no new query
print website.account.email_address

# first time registrar is referenced, so another query
print website.registrar.name

и так далее. Если вы выбрали selected related, то соединение выполняется за кулисами, и все эти внешние ключи автоматически отслеживаются и загружаются при первом запросе, поэтому выполняется только один запрос к базе данных. Так что в приведенном выше примере вы получите

# one database query with a join and all foreign keys followed
website = Website.objects.select_related().get(id=123)

# no additional query is needed because the data is already loaded
print website.account.username
print website.account.email_address
print website.registrar.name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...