Middleware in Django acts as a bridge between the request and response cycle. It lets you process incoming requests before they reach the view and modify outgoing responses before they’re sent to the client. In this guide, you’ll learn what middleware is and how to build a custom one in Django 5 using the latest approach.
Step 1: Understand What Middleware Does
Middleware is a lightweight layer that processes requests and responses globally. For example, it can log user activity, measure request time, or block unwanted IPs. Django automatically applies middleware to every request, so you can define logic that runs before and after each view.
Step 2: Create a New Django App for Middleware
You can place your custom middleware inside any Django app. Developers often create a “core” app to hold project-level utilities like middleware, context processors, and helpers.
Use the following command to create a new app:
python manage.py startapp core
Then, open your settings.py file and add it to the installed apps:
INSTALLED_APPS = [
# default Django apps ...
'core',
]
This ensures Django recognizes your new app and loads its components, including middleware.
Step 3: Write the Middleware Class
In Django 5, middleware follows a modern structure using __init__ and __call__ methods. Here’s an example:
import time
import logging
from django.http import HttpResponseForbidden
logger = logging.getLogger(__name__)
class SecurityAndMetricsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.blocked_ips = {"192.168.1.10", "10.0.0.5"}
def __call__(self, request):
ip = request.META.get("REMOTE_ADDR", "unknown")
start_time = time.time()
if ip in self.blocked_ips:
return HttpResponseForbidden("Access denied.")
response = self.get_response(request)
duration = (time.time() - start_time) * 1000
response["X-Request-Duration-ms"] = f"{duration:.2f}"
logger.info(f"{request.method} {request.path} took {duration:.2f} ms")
return response
This middleware measures how long each request takes and blocks specific IP addresses.
Step 4: Register the Middleware
Open your project’s settings.py file and add your middleware class to the MIDDLEWARE list:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"core.middleware.SecurityAndMetricsMiddleware",
]
The order matters—Django processes middleware top to bottom on the way in, and bottom to top on the way out.
Step 5: Test Your Middleware
Run your Django development server with:
python manage.py runserver
Make a few requests to your site. You’ll see timing information printed in your terminal logs and a new response header called X-Request-Duration-ms. If you try accessing the app from a blocked IP, Django will return a “403 Forbidden” response.
Conclusion
Custom middleware is a powerful feature in Django that gives you full control over the request and response cycle. By following these five steps, you can easily extend your project for logging, performance tracking, and security—using Django 5’s modern middleware design.