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

Ответ

Жизненный цикл обработки 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

Ответ 18+ 🔞

Давай разберём, как твой запрос по Django, сука, прёт от сервера до вьюхи и обратно, а то некоторые думают, что это магия какая-то, а там, блядь, конвейер чёткий, как у немцев.

Этапы, на которых всё может пиздануться:

  1. WSGI/ASGI Сервер: Это типа швейцар в дорогом клубе. Nginx или Apache смотрят на запрос, кивают и говорят: «Проходи, братан, к нашему вышибле Gunicorn». А тот уже толкает его прямо в пасть Django.
  2. WSGI Handler: Точка входа, wsgi.py. Тут рождается WSGIHandler — главный дирижёр этого ебаного оркестра. Он берёт запрос и начинает его пинать по цепочке.
  3. Middleware (Request): А вот и наш любимый фильтр. Представь, что запрос — это пацан, который идёт на тусовку. Каждый мидлварь — это охранник на входе. Один проверяет сессию («А ты кто такой?»), другой добавляет CSRF-токен («На, повесь бирку»), третий, блядь, замеряет время. Все они могут накостылять по request-у, прежде чем его пропустят дальше. Порядок в settings.py — святое, ёпта!
  4. URL-маршрутизация: Дальше запрос попадает в лабиринт urls.py. Django тыкает его в каждый path() и re_path(), пока не найдёт совпадение. Если не находит — пиздец, 404, «страница не найдена», иди нахуй.
  5. View (Представление): Ура, нашли! Вызывается вьюха. Ей передают этот уже потрёпанный жизнью объект HttpRequest. Здесь-то и происходит вся основная движуха: вытаскиваются данные из базы, проверяются формы, считается бизнес-логика. Главное — не забыть в конце что-то вернуть.
  6. Response: Вьюха обязана выплюнуть объект HttpResponse. Не вернёт — будет исключение, и пользователь увидит ошибку сервера вместо своей аватарки. Позор на твою голову!
  7. Middleware (Response): Ответ пошёл обратно. Теперь те же мидлвари, но в обратном порядке, могут его допилить. Добавить заголовок, сжать, ещё какую хуйню сделать.
  8. Отправка клиенту: WSGIHandler берёт готовый ответ и вышвыривает его обратно через Gunicorn и Nginx к пользователю, который уже заебался ждать.

Вот тебе пример мидлваря, который не делает ничего умного, но выглядит солидно:

# middleware.py
class SimpleTimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # Инициализация. Вызывается один раз при старте сервера.

    def __call__(self, request):
        # Код ДО вьюхи. Тут можно, например, время старта в request засунуть.
        start_time = time.time()

        response = self.get_response(request)  # Это магическая пауза, где вызывается вся остальная цепочка

        # Код ПОСЛЕ вьюхи. Всё, вьюха отработала, ответ есть.
        duration = time.time() - start_time
        response['X-Request-Duration'] = f'{duration:.3f}s'  # Прилепили свой заголовок

        return response

Вот и весь сказ, блядь. Никакой магии, просто чёткий порядок действий. Главное — не сломать эту цепочку, а то будет тебе не жизнь, а сплошной Internal Server Error.