Представление Django работает медленно
У меня есть представление в моем проекте Django:
@permission_required('storage.add_iteminrelease')
@transaction.atomic
def add_item_in_release(request, id):
release = get_object_or_404(Release, pk=id)
if (request.method == 'POST'):
add_item_in_release_form = ItemInReleaseForm(request.POST)
if add_item_in_release_form.is_valid():
add_item_in_release_form.instance.release = release
item = add_item_in_release_form.cleaned_data['item']
if item.count < add_item_in_release_form.cleaned_data['count']:
messages.add_message(request,
messages.ERROR,
'Кол-во выдачи не должно превышать ' + str(item.count))
return redirect('/releases/details/' + str(id) + '/')
item.count -= add_item_in_release_form.cleaned_data['count']
item.save()
item_in_release, create = ItemInRelease.objects.get_or_create(item=add_item_in_release_form.cleaned_data['item'],
release=release,
defaults={'count': add_item_in_release_form.cleaned_data['count']})
if not create:
item_in_release.count += add_item_in_release_form.cleaned_data['count']
item_in_release.save()
messages.add_message(request,
messages.SUCCESS,
'Позиция успешно добавлена')
return redirect('/releases/details/' + str(id) + '/')
messages.add_message(request,
messages.ERROR,
add_item_in_release_form.errors.as_data())
return redirect('/releases/details/' + str(id) + '/')
else:
add_item_in_release_form = ItemInReleaseForm()
return render(request,
'add_item_in_release.html',
{'add_item_in_release_form': add_item_in_release_form,
'id': id})
и соответствующий html-шаблон для этого шаблона, который загружается в модальное окно Bootstrap из другого шаблона:
<div class="modal fade" id="add-item" tabindex="-1" aria-labelledby="add-item-label" aria-hidden="true"
dats-bs-focus="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="add-item-label">Добавление позиции</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{% url 'storage:add-item-in-release' id %}" method="POST" class="form" novalidate>
<div class="modal-body">
{% csrf_token %}
<div class="form-floating w-100 mb-3">
{{ add_item_in_release_form.contract }}
<label for="count">Договор</label>
</div>
<div class="input-group flex-nowrap mb-3">
<div class="form-floating w-100">
<input class="form-control" id="item-datalist" placeholder="Позиция" name="item"
type="text" list="items" autocomplete="off">
<datalist id="items">
{% for i in add_item_in_release_form.fields.item.queryset %}
<option data-value="{{ i.id }}" data-count="{{ i.count }}" data-contract="{{ i.contract }}" value="{{ i.item.manufacturer.name }} {{ i.item.article }} {{ i.contract }}"></option>
{% endfor %}
</datalist>
<label for="item-datalist">Позиция</label>
</div>
<button class="btn btn-outline-secondary" type="button" id="clear-input" title="Очистить">
<i class="fa fa-eraser"></i>
</button>
</div>
<div class="input-group flex-nowrap mb-3">
<div class="form-floating w-100">
{{ add_item_in_release_form.count }}
<label for="count">Кол-во</label>
</div>
<span class="input-group-text w-25" id="count-label" title="Максимальное кол-во"></span>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-outline-success">Добавить</button>
<button type="button" class="btn btn-outline-primary" data-bs-dismiss="modal">Отменить</button>
</div>
</form>
</div>
</div>
</div>
Когда я вызываю это представление, страница загружается до 10 секунд, но другие страницы загружаются мгновенно. Почему этот код работает так медленно? Может быть, это потому, что у меня около 1000 опций в datalist? Я не понимаю.
Похоже, что наблюдаемая вами медлительность может быть вызвана несколькими причинами:
Валидация формы: Похоже, что ваше представление выполняет валидацию формы, которая включает операции с базой данных (например, запрос
ItemInRelease
). Это может замедлить время отклика, особенно если имеется много запросов к базе данных или сложная логика валидации.Запросы к базе данных: Как вы уже упоминали, наличие около 1000 опций в списке данных также может способствовать медлительности, особенно если каждая опция требует запроса к базе данных для получения соответствующих данных. Рассмотрите возможность оптимизации запросов к базе данных или уменьшения количества опций, если это возможно.
Перенаправления: Представление выполняет перенаправления после обработки отправленных форм или при возникновении ошибок. Перенаправления добавляют дополнительные обходы между клиентом и сервером, что может увеличить время загрузки.
Чтобы повысить производительность представления, вы можете рассмотреть следующие оптимизации:
Reduce Database Queries: Старайтесь минимизировать количество запросов к базе данных, особенно в циклах или повторяющихся операциях. Используйте предварительную выборку наборов запросов Django (
select_related
илиprefetch_related
) для эффективной выборки связанных объектов.Пакетная обработка: Если возможно, выполняйте пакетную обработку нескольких операций с базой данных вместе, чтобы уменьшить накладные расходы на выполнение отдельных запросов.
Кэширование результатов запросов: Рассмотрите возможность кэширования часто используемых данных или результатов запросов с помощью фреймворка кэширования Django. Это поможет снизить нагрузку на вашу базу данных и ускорить последующие запросы.
Асинхронная обработка: Если некоторые операции выполняются особенно медленно или требуют много ресурсов, подумайте о том, чтобы переложить их на фоновые задачи с помощью
celery
Django или аналогичных асинхронных очередей задач.Оптимизация клиентской стороны: Рассмотрите возможность оптимизации кода на стороне клиента, особенно если JavaScript задействован в обработке отправки форм или взаимодействии с даталистом.
Выполнив эти оптимизации, вы сможете повысить производительность вашего представления Django и значительно сократить время загрузки.
Код работает медленно не потому, что в списке 1000 вариантов (что является несколько плохим дизайном фронтенда / UI), а потому, что вы так часто запрашиваете ForeignKeys:
<datalist id="items">
{% for i in add_item_in_release_form.fields.item.queryset %}
<option data-value="{{ i.id }}" data-count="{{ i.count }}" data-contract="{{ i.contract }}" value="{{ i.item.manufacturer.name }} {{ i.item.article }} {{ i.contract }}"></option>
{% endfor %}
</datalist>
По сути, вы должны загрузить в fields.item.queryset
метод с именем select_releated
и передать manufacturer
и article
. Не уверен, как это сделать на форме Django, но уверен, что это возможно. Возможно, можно попробовать переопределить магический субметод __init__
, но это, вероятно, не самый оптимальный способ (он будет быстрее, но Query будет вызван дважды, потому что для этого есть другой метод).