Как в проекте на Django показывать индикатор загрузки (спиннер или прогресс) при загрузке страницы или данных?

Создаю сайт на Django. Нужно выполнить парсинг данных по заданным параметрам и отобразить их на странице — процесс занимает примерно 5 секунд. Как реализовать индикатор загрузки, который автоматически завершится по окончании парсинга и покажет информацию, полученную скриптом?
  • 20 февраля 2026 г. 18:01
Ответы на вопрос 2
Коротко — не держите пользователя в "пустом" браузере пока сервер парсит. Делайте быстрый initial response, показывающий спиннер, и либо:
- делайте запрос на парсинг через AJAX (fetch / jQuery) и по его окончании прячете спиннер и вставляете результат; либо
- для продвинутого контроля прогресса — запускайте задачу в фоне (Celery/RQ) и опрашивайте статус (polling) или используйте WebSocket/SSE для пуша прогресса.

Ниже — простая и надёжная реализация через AJAX (подходит для ~5 секунд).

1) Django view (возвращает JSON или HTML-фрагмент)
views.py
```
import json
from django.http import JsonResponse
from django.template.loader import render_to_string
from django.views.decorators.http import require_POST

@require_POST
def parse_view(request):
    data = json.loads(request.body.decode())
    # пример парсинга, который занимает ~5s
    result = do_parsing(data.get('param'))  # ваша функция
    # можно вернуть JSON-структуру или готовый HTML-фрагмент
    html = render_to_string('partials/result.html', {'items': result})
    return JsonResponse({'html': html})
```

urls.py
```
from django.urls import path
from . import views

urlpatterns = [
    path('parse/', views.parse_view, name='parse'),
]
```

2) Шаблон с кнопкой, спиннером и контейнером для результата
template.html
```
<html>
<head>
  <!-- Подключите Bootstrap CSS если хотите готовый спиннер -->
</head>
<body>
  <form id="parseForm">
    <input name="param" id="param" value="..." />
    <button type="submit">Запустить парсинг</button>
  </form>

  <!-- Спиннер (скрыт по умолчанию) -->
  <div id="spinner" style="display:none;">
    <!-- Пример простого CSS-спиннера / или Bootstrap:
    <div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>
    -->
    Загрузка...
  </div>

  <!-- Контейнер для результата -->
  <div id="result"></div>

  <script>
    function getCookie(name) {
      let cookieValue = null;
      if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
          const cookie = cookies[i].trim();
          if (cookie.substring(0, name.length + 1) === (name + '=')) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
            break;
          }
        }
      }
      return cookieValue;
    }
    const csrftoken = getCookie('csrftoken');

    document.getElementById('parseForm').addEventListener('submit', function(e){
      e.preventDefault();
      const param = document.getElementById('param').value;
      document.getElementById('spinner').style.display = 'block';
      fetch('/parse/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRFToken': csrftoken
        },
        body: JSON.stringify({param: param})
      }).then(resp => {
        if (!resp.ok) throw new Error('Network error');
        return resp.json();
      }).then(data => {
        document.getElementById('spinner').style.display = 'none';
        document.getElementById('result').innerHTML = data.html;
      }).catch(err => {
        document.getElementById('spinner').style.display = 'none';
        alert('Ошибка: ' + err);
      });
    });
  </script>
</body>
</html>
```

Пояснения и советы
- CSRF: при POST из JS не забудьте отправлять X-CSRFToken (пример функции getCookie выше).
- Возвращать HTML-фрагмент удобно — сервер рендерит шаблон с данными, клиент вставляет его в страницу. Можно также вернуть JSON и рендерить на клиенте.
- Для простого 5-секундного процесса такой синхронный AJAX-запрос — вполне нормален. Но если операции могут длиться дольше или число одновременных запросов растёт, лучше запускать задачу в фоне (Celery) и:
  - вернуть task_id сразу,
  - опрашивать статус (/task-status/<id>/) пока не готов,
  - или использовать WebSocket / Server-Sent Events для моментального пуша прогресса.
- Если нужно показывать процент выполнения — либо парсер должен отдавать прогресс (через фоновые задачи или SSE/WebSocket), либо делайте многократные этапы с обновлением прогресса на сервере.

Альтернатива — StreamingHttpResponse: сервер частями отправляет HTML (например сначала страница со спиннером), затем через flush присылает результаты. Это сложнее и чаще не нужно.

Если нужно, могу дать пример с Celery + polling или с WebSocket (Django Channels) для отображения процента.
Это делается на фронте с помощью js, django тут боком. А вообще, научись уже гуглить готовые примеры или решения, а сейчас вообще, про подобное без проблем можно получить ответ от LLM,
Похожие вопросы