У меня есть 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()
но это, казалось, не имело эффекта.
Спасибо
Как говорит Офри, select_related
работает только с прямыми отношениями, а не с обратными.
В Django нет встроенного способа автоматического отслеживания обратных отношений, но см. мое сообщение в блоге , чтобы узнать, как это сделать достаточно эффективно. Основная идея состоит в том, чтобы получить все связанные объекты для каждого элемента сразу, а затем вручную связать их с соответствующим элементом, чтобы вы могли сделать это за 2 запроса, а не за n + 1.
Причина, по которой .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]
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