0 day streak
python / expert
Snippet

Custom Django Middleware with Request/Response Processing Pipeline

Django middleware sits between the web server and your view, processing every request and response. This expert-level middleware implements rate limiting using an in-memory counter, tracks request counts per IP address, blocks excessive requests with HTTP 429, and injects custom headers into responses. The __init__ receives the get_response callable, __call__ processes each request/response pair, and process_exception handles unexpected errors globally.

snippet.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin
class RateLimitMiddleware(MiddlewareMixin):
def __init__(self, get_response):
self.get_response = get_response
self.request_counts = {}
def __call__(self, request):
client_ip = request.META.get('REMOTE_ADDR')
self.request_counts[client_ip] = self.request_counts.get(client_ip, 0) + 1
if self.request_counts[client_ip] > 100:
return JsonResponse({'error': 'Rate limit exceeded'}, status=429)
response = self.get_response(request)
response['X-Request-Count'] = self.request_counts[client_ip]
return response
def process_exception(self, request, exception):
return JsonResponse({'error': str(exception)}, status=500)
django
Breakdown
1
from django.utils.deprecation import MiddlewareMixin
Imports MiddlewareMixin for compatibility with Django's middleware framework
2
def __init__(self, get_response):
Initializer receives the next middleware/view in the chain as get_response
3
self.request_counts = {}
In-memory dictionary storing request counts per client IP
4
client_ip = request.META.get('REMOTE_ADDR')
Extracts client IP from request metadata for rate tracking
5
if self.request_counts[client_ip] > 100:
Checks if client has exceeded the rate limit threshold
6
return JsonResponse({'error': 'Rate limit exceeded'}, status=429)
Returns 429 Too Many Requests when limit is exceeded
7
response['X-Request-Count'] = self.request_counts[client_ip]
Injects custom header with current request count into response
8
def process_exception(self, request, exception):
Override to catch and transform unhandled exceptions globally