CodeOath
← All posts
Python70 min total · 18 parts

Django Fundamentals: MVT Architecture, the ORM, and Middleware

Contents — Part 15 of 18: Middleware
Part 15 of 18 · ~1 min

Middleware

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
]

Listed top to bottom, each middleware wraps everything below it — a request passes down through this list in order, and the response passes back up through it in reverse, identical in shape to ASP.NET Core's and Express's pipelines (see Middleware Pipelines Compared for all three side by side). AuthenticationMiddleware must run after SessionMiddleware, since it reads the logged-in user's ID out of the session — a genuinely common misconfiguration when adding custom middleware is placing it before the middleware whose data it depends on.

Writing a custom middleware

class RequestTimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response   # called once, when Django starts

    def __call__(self, request):
        start = time.perf_counter()
        response = self.get_response(request)   # everything "below" this middleware runs here
        response["X-Response-Time-Ms"] = str(int((time.perf_counter() - start) * 1000))
        return response

__init__ runs exactly once, at server startup — this is where one-time setup belongs, not __call__, which runs on every single request. Code before the self.get_response(request) call runs on the way down (before the view); code after it runs on the way back up (after the view has produced a response).