Django formet, запросы для реляционного поля для каждой формы
Models.py
class Material(BaseModelClass):
material = models.CharField(max_length=25, verbose_name='Material')
def __str__(self):
return self.material
class PurOrder(BaseModelClass):
order_number = models.CharField(max_length=25)
class PurOrderItem(BaseModelClass):
order = models.ForeignKey(PurOrder, on_delete=models.CASCADE)
material = models.ForeignKey(Material, on_delete=models.PROTECT)
Я создал форму PurOrder и набор форм PurOrderItem
PurOrderForm = modelform_factory(PurOrder, fields=('order_number',))
PurOrderFormset = inlineformset_factory(PurOrder, PurOrderItem,fields=('material',))
Инициализировали их следующим образом.
form = PurOrderForm(instance=order_instance)
queryset = order_instance.purorderitem_set.all().select_related('material',)
formset = PurOrderFormset(instance=order_instance, queryset=queryset)
Эта установка обойдется мне в 22 запроса, если имеется 20 PurOrderItem для выбранного purorder.
- 1 для экземпляра PurOrder,
- 1 для экземпляра PurOrderItem
- 20 для выбранных материалов для этих продуктов PurOrderItem.
Подумайте об этом, если есть 1000 PurOrderItem
С предоставленным select_related, он добавляет материал в PurOrderItemselect, но когда дело доходит до его отображения, я думаю, он снова запрашивает.
Я использую django-autocomplete-light, поэтому он избавляет меня от запроса всех экземпляров материала, но он продолжает запрашивать выбранный материал, чтобы отображать его, даже если я выбираю_соединенный материал.
В идеале я бы выбрал экземпляр PurOrder с предварительно выбранным purorderitem и связанными с ним материалами, это означает 3 запроса. Приобретенный purorderitem и материал будут использоваться, когда это будет их очередь.
Пожалуйста, посоветуйте мне способ избежать выбора выбранного запроса.
Примечание. Я стараюсь избегать кэширования здесь.
ОБНОВИТЬ
Много времени после того, как я создал этот вопрос, и я попробовал предоставленные решения. Проблема в том, что формы формы не знают друг о друге. Таким образом, при условии, что выбранный запрос выбранный_религированный или предвыборный поиск не передается формам форм.
Ответы
Ответ 1
Ты в порядке. Этот код будет стоить вам всего 3 запроса. Как вы можете видеть в документации select_related():
Возвращает QuerySet, который будет "следовать" отношениям с внешним ключом, выбирая дополнительные данные связанных объектов, когда он выполняет свой запрос. Это ускоритель производительности, который приводит к одному более сложному запросу, но означает, что позднее использование отношений внешнего ключа не потребует запросов к базе данных.
Это означает, что ваш код будет предусматривать mysql join
и приведет к набору данных со всеми данными. Таким образом, я вижу, что ваш код довольно хорош.
Я предлагаю вам использовать какой-то профиль, например django-silk, чтобы узнать, сколько запросов создается.
Сноска:
Как вы можете видеть в документации prefetch_related(), разница между prefetch_related()
и select_related()
заключается в том, как они преформируют соединение:
Это (prefetch_related) имеет аналогичную цель для select_related, поскольку оба они предназначены для предотвращения потопов запросов к базе данных, вызванных доступом к связанным объектам, но стратегия совершенно иная.
...
select_related работает путем создания соединения SQL и включения полей связанного объекта в оператор SELECT. По этой причине select_related получает связанные объекты в одном запросе базы данных.
...
prefetch_related, с другой стороны, выполняет отдельный поиск для каждой связи и выполняет "объединение в Python.
Таким образом, если вам нужны отношения " one-to-one
, select_related
является наиболее эффективным способом запроса отношений.