Короткий ответ
Middleware реализуется как вызываемый класс с методом __call__, принимающий get_response в конструкторе; его нужно разместить как можно раньше в MIDDLEWARE, чтобы замер включал время работы всех последующих middleware и view.
Как это работает подробнее
Современный стиль middleware в Django — класс с __init__(self, get_response) и __call__(self, request), который вызывает self.get_response(request) для передачи запроса дальше по цепочке и получает response для пост-обработки.
Пример кода
example.py
import time
class TimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.monotonic()
response = self.get_response(request)
duration_ms = (time.monotonic() - start) * 1000
response["X-Response-Time-Ms"] = f"{duration_ms:.1f}"
return response
# settings.py
MIDDLEWARE = [
"myapp.middleware.TimingMiddleware", # одним из первых
"django.middleware.security.SecurityMiddleware",
]
# Проверка: в ответе на любой запрос должен появиться заголовок X-Response-Time-Ms.Что использовать на практике
- Практика. Замер времени логично делать «снаружи» (ближе к началу списка
MIDDLEWARE), чтобы учесть работу всех остальных middleware; добавление заголовкаX-Response-Timeв ответ помогает диагностировать медленные запросы в production без дополнительного профилирования.
Подводные камни
- Риск. Размещают измеряющий middleware слишком «глубоко» в списке (близко к view), из-за чего он не учитывает время работы middleware аутентификации/сессий, которые могут быть источником задержки; забывают, что middleware должен быть вызываемым объектом, а не просто функцией-обработчиком без
get_response.