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 является наиболее эффективным способом запроса отношений.