Custom Middleware0%
Custom Middleware
Beginner12 min read•Updated: Jul 11, 2026
Custom Middleware
Django processes incoming HTTP requests and outgoing HTTP responses through an extensible pipeline known as Middleware. Each middleware component behaves like an onion layer: it can inspect, alter, or short-circuit incoming requests before they reach the view, and post-process outgoing responses before they are returned to the client browser.
1. The Middleware Execution Pipeline
Output
Incoming Request:
Client ──► [SecurityMiddleware] ──► [SessionMiddleware] ──► [AuthMiddleware] ──► View Function
│
Outgoing Response: ▼
Client ◄── [SecurityMiddleware] ◄── [SessionMiddleware] ◄── [AuthMiddleware] ◄── Response
- Top-to-Bottom on Requests: Middlewares execute in the exact order listed in
settings.MIDDLEWARE. - Bottom-to-Top on Responses: Middlewares execute in reverse order when returning responses.
2. Anatomy of Modern Callable Middleware
Modern Django middleware is structured as a Python callable (function or class) taking get_response:
Python
# config/middleware/request_timer.py
import time
import logging
logger = logging.getLogger("django.performance")
class PerformanceTimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization upon server boot
def __call__(self, request):
# 1. Code executed BEFORE the view is called:
start_time = time.monotonic()
# 2. Hand over request to next layer (or view)
response = self.get_response(request)
# 3. Code executed AFTER the view completes:
duration = time.monotonic() - start_time
duration_ms = round(duration * 1000, 2)
# Attach custom performance header to outgoing HTTP response
response["X-Response-Time-Ms"] = str(duration_ms)
if duration_ms > 500:
logger.warning(
f"Slow Request Detected: {request.method} {request.path} took {duration_ms}ms"
)
return response
3. Special Middleware Hooks
Classes can implement specialized hook methods for specific interception points:
process_view(request, view_func, view_args, view_kwargs): Called just before Django calls the view function. Returning anHttpResponsebypasses the view entirely.process_exception(request, exception): Called when a view raises an unhandled exception. Ideal for reporting crashes to Sentry or Datadog.process_template_response(request, response): Called if the view returned aTemplateResponseobject, allowing manipulation of template context before rendering.
4. IP Whitelisting & API Rate Limiting Middleware
Python
# config/middleware/ip_guard.py
from django.http import HttpResponseForbidden
from django.conf import settings
class IPWhitelistMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Restrict /admin/ access to corporate VPN IP ranges
if request.path.startswith("/admin/"):
client_ip = self.get_client_ip(request)
if client_ip not in settings.ADMIN_IP_WHITELIST:
return HttpResponseForbidden("Access Denied: IP address not in corporate whitelist.")
return self.get_response(request)
def get_client_ip(self, request):
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
if x_forwarded_for:
return x_forwarded_for.split(",")[0].strip()
return request.META.get("REMOTE_ADDR")
5. Registering Custom Middleware in settings.py
Python
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
# Custom Enterprise Middlewares:
"config.middleware.request_timer.PerformanceTimingMiddleware",
"config.middleware.ip_guard.IPWhitelistMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
]
Interactive Quiz
Practice Quiz
Question 1
In what order do middleware components execute during the lifecycle of an HTTP request and response?
Question 2
What does returning an HttpResponse directly from a middleware before calling get_response(request) do?
Question 3
How do you extract the real client IP address when Django sits behind a reverse proxy (e.g. Nginx or Cloudflare)?
Question 4
When is the process_exception(request, exception) hook called?
Question 5
Why is __init__(self, get_response) only executed once in class-based middleware?
Next Lesson
CSRF Protection
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
Related Lessons
| Previous Lesson | Next Lesson |
|---|---|
| Routing APIs with DRF | CSRF Protection |
Practice Quiz
Test your understanding of this lesson with 5 questions. Each question has one correct answer.