Astrohas
@Astrohas
Python/Django Developer

Как оптимизировать запрос?

Итак модели
class Modal(models.Model):
    slug = models.SlugField(max_length=255, blank=True)

class ModalItem(models.Model):
    of = models.ForeignKey(Modal, related_name="items")
    to = models.ForeignKey(Modal, related_name="lasts", blank=True, null=True)
    is_product = models.BooleanField(verbose_name="Is product", default=False)


а также функция

active_modal = get_object_or_404(Modal, slug="connect-modal")
all_modals = list()
all_modals.append(active_modal)

def get_referenced(modal):
        for item in modal.items.all():
            if not item.is_product and item.to is not None:
                all_modals.append(item.to)
                get_referenced(item.to)
 get_referenced(active_modal)


Кроме этого внутри шаблона для каждого модалf идет цикл
{% for modal in modals %}
  {% for item in modal.modalitem_set.all %}


------
Проблема в том что это все генерирует 1400 запросов к базе данных (хотя величины таблиц не превышают и 100). Есть ли способ как-то это оптимизировать?
  • Вопрос задан
  • 268 просмотров
Решения вопроса 1
Astrohas
@Astrohas Автор вопроса
Python/Django Developer
Пока функцию оптимизировал так
active_modal = get_object_or_404(Modal, slug="connect-modal")
    all_modals = list()
    all_modals.append(active_modal.id)

    def get_referenced(modal):
        for item in modal.items.all():
            if not item.is_product and item.to_id is not None:
                all_modals.append(item.to_id)
                get_referenced(item.to)


    get_referenced(active_modal)
    modals = Modal.objects.filter(pk__in=all_modals)
    print(all_modals)

Результат -> 768 запросов (вдвое меньше). Подумываю над оптимизацией шаблона
UPD 2) Кеширование объектов. Сделал выборку данных одним запросом, потом, питоном все monkey_patching-ом заполнил
for modal in modals:
        modal.items_cached = [item for item in items if item.of_id == modal.id]

Т.е вместо modal.items.all стало modals.items_cached
62 запросов
UPD 3) вместо все фигни сделал так
active_modal = get_object_or_404(Modal, slug="connect-modal")

    modals_ids = list()
    modals_ids.append(active_modal.id)

    all_modals = list(Modal.objects.all())
    all_modals.append(active_modal)

    items = ModalItem.objects.all()
    for modal in all_modals:
        modal.items_cached = [item for item in items if item.of_id == modal.id]

    def get_referenced(modal):

        for item in modal.items_cached:
            if not item.is_product and item.to_id is not None:
                modals_ids.append(item.to_id)

                for modal in all_modals:

                    if modal.id == item.to_id:
                        get_referenced(modal)
                        break

    get_referenced(active_modal)

    modals = [modal for modal in all_modals if modal.id in modals_ids]


3 запроса
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
DarkRaven
@DarkRaven
разработка программного обеспечения
Вам нужно посмотреть в сторону Eager Loading или пересмотреть в целом получение нужных данных
Ответ написан
Комментировать
sergey-gornostaev
@sergey-gornostaev Куратор тега Django
Седой и строгий
Не используете django-mptt для работы с иерархическими данными.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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