получите объекты внешнего ключа в едином запросе - Django

У меня есть 2 модели в моем коде django:

class ModelA(models.Model):
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    created_by = models.ForeignKey(User)

class ModelB(models.Model):
    category = models.CharField(max_length=255)
    modela_link = models.ForeignKey(ModelA, 'modelb_link')
    functions = models.CharField(max_length=255)
    created_by = models.ForeignKey(User)

Скажите, что ModelA имеет 100 записей, все из которых могут или не могут иметь ссылок на ModelB

Теперь скажите, что я хочу получить список каждой записи ModelA наряду с данными ModelB

Я сделал бы:

list_a = ModelA.objects.all()

Затем для получения данных для ModelB я должен был бы сделать

for i in list_a:
    i.additional_data = i.modelb_link.all()

Однако это выполняет запрос на каждом экземпляре меня. Таким образом создание 101 запроса для выполнения.

Есть ли любой способ выполнить это все во всего 1 запросе. Или по крайней мере меньше, чем 101 запрос.

Я попытался включить ModelA.objects.select_related().all() но это, казалось, не имело эффекта.

Спасибо

12
задан Serjik 19 December 2015 в 11:29
поделиться

3 ответа

Как говорит Офри, select_related работает только с прямыми отношениями, а не с обратными.

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

7
ответ дан 2 December 2019 в 22:22
поделиться

Причина, по которой .select_related() не работает, заключается в том, что .select_related() используется для отслеживания внешних ключей. Ваша ModelA не имеет внешнего ключа к ModelB. Это ModelB имеет внешний ключ к ModelA. (поэтому экземпляр ModelA может иметь несколько экземпляров ModelB, связанных с ним).

Вы можете использовать это для выполнения 2 запросов и немного кода на python:

list_b = ModelB.objects.all()
list_a = ModelA.objects.all()
for a in list_a:
    a.additional_data = [b for b in list_b if b.modela_link_id==a.id]
1
ответ дан 2 December 2019 в 22:22
поделиться

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

from django.db import connection
cur=connection.cursor()
cur.execute(query)
rows = cur.fetchall()

ваш запрос должен выглядеть так ( для MySQL )

SELECT * FROM appname_modela INNER JOIN appname_modelb ON appname_modela.id=appname_modelb.modela_link_id
2
ответ дан 2 December 2019 в 22:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: