Как устроен процесс обработки HTTP-запроса в Django

«Как устроен процесс обработки HTTP-запроса в Django» — вопрос из категории Django, который задают на 22% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Жизненный цикл обработки HTTP-запроса в Django представляет собой конвейер, управляемый через интерфейс WSGI (или ASGI для асинхронных приложений).

Основные этапы:

  1. WSGI/ASGI Сервер: Веб-сервер (например, Nginx) передает запрос WSGI-серверу (Gunicorn, uWSGI), который взаимодействует с Django.
  2. WSGI Handler: Запрос поступает в точку входа Django (wsgi.py). Здесь создается экземпляр WSGIHandler, который управляет всем циклом.
  3. Middleware (Request): Запрос проходит через все промежуточные слои (middleware) из settings.py. Каждый middleware может модифицировать объект request перед тем, как он достигнет view.
  4. URL-маршрутизация (Routing): Django пытается сопоставить URL запроса с шаблонами, определенными в urls.py. Этот процесс называется "URL resolving".
  5. View (Представление): Если совпадение найдено, Django вызывает соответствующую функцию или класс-представление (view), передавая ей объект HttpRequest.
  6. Бизнес-логика: View выполняет основную логику: обращается к моделям для работы с базой данных, обрабатывает данные форм, вызывает сервисы и т.д.
  7. Response: View должна вернуть экземпляр объекта HttpResponse (или его подкласса, например, JsonResponse).
  8. Middleware (Response): Объект response проходит через все middleware в обратном порядке. На этом этапе они могут изменять ответ (например, добавлять заголовки).
  9. Отправка клиенту: WSGIHandler отправляет финальный HTTP-ответ WSGI-серверу, который передает его клиенту.

Пример Middleware:

# middleware.py
class SimpleTimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # Одноразовая настройка при старте сервера

    def __call__(self, request):
        # Код, выполняемый перед вызовом view
        # Например, можно замерить время начала обработки

        response = self.get_response(request)

        # Код, выполняемый после вызова view
        # Например, можно добавить кастомный заголовок в ответ
        response['X-Custom-Header'] = 'my-value'

        return response