$ cat /posts/django-middleware-request-and-response-processing.md

Django Middleware: Request and Response Processing

drwxr-xr-x2026-01-235 min0 views
Django Middleware: Request and Response Processing

Django middleware provides hooks into request and response processing enabling application-wide functionality that executes for every HTTP transaction. Middleware components form processing chains wrapping views with layers of functionality including authentication verification, session management, CSRF protection, security headers, logging, and performance monitoring. This powerful architecture enables cross-cutting concerns implementation without modifying individual views maintaining clean separation between business logic and infrastructure concerns. This comprehensive guide explores Django 6.0 middleware system including understanding middleware execution order and processing phases, using built-in middleware for security and optimization, creating custom middleware for logging and monitoring, implementing authentication and authorization middleware, adding custom headers and modifying responses, exception handling and error processing, performance profiling middleware, and best practices for middleware development. Mastering middleware unlocks powerful capabilities for implementing application-wide functionality efficiently transforming requests and responses consistently across entire applications from simple logging to complex security policies.

Understanding Middleware

Middleware are Python classes that process requests before they reach views and responses before they're sent to clients. Each middleware component can modify requests, generate responses short-circuiting the process, or augment responses. Middleware executes in the order defined in settings during request processing and in reverse order during response processing creating an onion-like architecture. Django includes essential middleware for security, sessions, authentication, CSRF protection, and common features.

pythonmiddleware_basics.py
# settings.py - Middleware configuration
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# Basic middleware structure
class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization
    
    def __call__(self, request):
        # Code executed for each request before the view
        
        response = self.get_response(request)
        
        # Code executed for each request/response after the view
        
        return response

# Middleware with process methods
class AdvancedMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Process request
        response = self.get_response(request)
        return response
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        # Called just before Django calls the view
        # Return None to continue, or HttpResponse to short-circuit
        return None
    
    def process_exception(self, request, exception):
        # Called when view raises exception
        # Return None or HttpResponse
        return None
    
    def process_template_response(self, request, response):
        # Called for responses with render() method
        return response

# Execution order
"""
Request Phase (top to bottom):
1. SecurityMiddleware
2. SessionMiddleware
3. CommonMiddleware
4. CsrfViewMiddleware
5. AuthenticationMiddleware
6. MessageMiddleware
7. View executes

Response Phase (bottom to top):
7. MessageMiddleware
6. AuthenticationMiddleware
5. CsrfViewMiddleware
4. CommonMiddleware
3. SessionMiddleware
2. SecurityMiddleware
1. Client receives response
"""
Middleware order matters significantly. SecurityMiddleware should be first, SessionMiddleware before AuthenticationMiddleware, and CSRF middleware after SessionMiddleware. Incorrect ordering can cause authentication failures or security vulnerabilities.

Creating Custom Middleware

Custom middleware implements application-specific functionality affecting all requests and responses. Common use cases include request logging, performance monitoring, custom authentication, user tracking, response modification, and API throttling. Middleware provides centralized locations for cross-cutting concerns avoiding code duplication across views while maintaining separation of concerns.

pythoncustom_middleware.py
# Logging middleware
import logging
import time

logger = logging.getLogger(__name__)

class RequestLoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Log request
        start_time = time.time()
        logger.info(f'{request.method} {request.path}')
        
        response = self.get_response(request)
        
        # Log response
        duration = time.time() - start_time
        logger.info(
            f'{request.method} {request.path} '
            f'Status: {response.status_code} '
            f'Duration: {duration:.2f}s'
        )
        
        return response

# Performance monitoring middleware
class PerformanceMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        start_time = time.time()
        
        response = self.get_response(request)
        
        duration = time.time() - start_time
        
        # Add performance header
        response['X-Page-Generation-Duration'] = str(duration)
        
        # Log slow requests
        if duration > 1.0:  # Slower than 1 second
            logger.warning(
                f'Slow request: {request.path} took {duration:.2f}s'
            )
        
        return response

# Custom header middleware
class CustomHeaderMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        response = self.get_response(request)
        
        # Add custom headers
        response['X-Custom-Header'] = 'MyApp 1.0'
        response['X-Request-ID'] = str(uuid.uuid4())
        
        return response

# User tracking middleware
class UserTrackingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Track user activity
        if request.user.is_authenticated:
            from .models import UserActivity
            UserActivity.objects.create(
                user=request.user,
                path=request.path,
                method=request.method,
                ip_address=self.get_client_ip(request)
            )
        
        response = self.get_response(request)
        return response
    
    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

# API throttling middleware
from django.core.cache import cache
from django.http import HttpResponse

class ThrottleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.rate_limit = 100  # requests per minute
    
    def __call__(self, request):
        if request.path.startswith('/api/'):
            ip = self.get_client_ip(request)
            cache_key = f'throttle_{ip}'
            
            requests = cache.get(cache_key, 0)
            
            if requests >= self.rate_limit:
                return HttpResponse(
                    'Rate limit exceeded',
                    status=429
                )
            
            cache.set(cache_key, requests + 1, 60)  # 60 seconds
        
        response = self.get_response(request)
        return response
    
    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]
        return request.META.get('REMOTE_ADDR')

# Maintenance mode middleware
from django.shortcuts import render

class MaintenanceModeMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Check if maintenance mode is enabled
        from django.conf import settings
        
        if getattr(settings, 'MAINTENANCE_MODE', False):
            # Allow staff users
            if not request.user.is_staff:
                return render(
                    request,
                    'maintenance.html',
                    status=503
                )
        
        response = self.get_response(request)
        return response

Exception Handling Middleware

Middleware can catch and handle exceptions raised during request processing providing centralized error handling, logging, and custom error responses. The process_exception method receives exceptions before they bubble up enabling custom error pages, error notification, logging, and graceful degradation. This approach centralizes error handling logic avoiding repetition across views.

pythonexception_middleware.py
# Exception handling middleware
import logging
import traceback
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render

logger = logging.getLogger(__name__)

class ExceptionHandlingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        try:
            response = self.get_response(request)
            return response
        except Exception as e:
            return self.handle_exception(request, e)
    
    def process_exception(self, request, exception):
        # Log exception
        logger.error(
            f'Exception in {request.path}: {str(exception)}\n'
            f'{traceback.format_exc()}'
        )
        
        # Send error notification email
        if not settings.DEBUG:
            self.send_error_email(request, exception)
        
        # Return custom error response
        if request.path.startswith('/api/'):
            return JsonResponse({
                'error': 'Internal server error',
                'message': str(exception) if settings.DEBUG else 'An error occurred'
            }, status=500)
        
        return render(request, '500.html', {
            'exception': exception if settings.DEBUG else None
        }, status=500)
    
    def send_error_email(self, request, exception):
        from django.core.mail import mail_admins
        subject = f'Error on {request.path}'
        message = f'''
        URL: {request.build_absolute_uri()}
        User: {request.user}
        Exception: {str(exception)}
        Traceback:
        {traceback.format_exc()}
        '''
        mail_admins(subject, message, fail_silently=True)

# Database error handling
from django.db import OperationalError

class DatabaseErrorMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def process_exception(self, request, exception):
        if isinstance(exception, OperationalError):
            logger.critical('Database connection error')
            return render(
                request,
                'errors/database_error.html',
                status=503
            )
        return None

# Custom 404 middleware
from django.http import Http404

class Custom404Middleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def process_exception(self, request, exception):
        if isinstance(exception, Http404):
            # Log 404 errors
            logger.warning(f'404 error: {request.path}')
            
            # Suggest similar pages
            suggestions = self.find_suggestions(request.path)
            
            return render(request, '404.html', {
                'suggestions': suggestions
            }, status=404)
        return None
    
    def find_suggestions(self, path):
        # Find similar URLs
        from django.urls import get_resolver
        resolver = get_resolver()
        # Implementation to find similar paths
        return []

Authentication and Authorization Middleware

Custom authentication middleware enables alternative authentication schemes beyond Django's default session-based authentication. Common patterns include token authentication for APIs, JWT verification, API key validation, and IP-based access control. Middleware provides centralized authentication logic executing before views ensuring consistent security across applications.

pythonauth_middleware.py
# Token authentication middleware
from django.http import JsonResponse
from django.contrib.auth.models import AnonymousUser

class TokenAuthenticationMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Check for API token in header
        token = request.META.get('HTTP_AUTHORIZATION')
        
        if token and token.startswith('Bearer '):
            token_key = token.split(' ')[1]
            user = self.authenticate_token(token_key)
            
            if user:
                request.user = user
            else:
                return JsonResponse(
                    {'error': 'Invalid token'},
                    status=401
                )
        
        response = self.get_response(request)
        return response
    
    def authenticate_token(self, token_key):
        from .models import APIToken
        try:
            api_token = APIToken.objects.select_related('user').get(
                key=token_key,
                is_active=True
            )
            return api_token.user
        except APIToken.DoesNotExist:
            return None

# IP whitelist middleware
class IPWhitelistMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.whitelist = ['127.0.0.1', '::1']  # localhost
    
    def __call__(self, request):
        ip = self.get_client_ip(request)
        
        # Check admin access
        if request.path.startswith('/admin/'):
            if ip not in self.whitelist:
                return HttpResponse('Access denied', status=403)
        
        response = self.get_response(request)
        return response
    
    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]
        return request.META.get('REMOTE_ADDR')

# JWT authentication middleware
import jwt
from django.conf import settings

class JWTAuthenticationMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        token = request.META.get('HTTP_AUTHORIZATION')
        
        if token and token.startswith('Bearer '):
            token_key = token.split(' ')[1]
            
            try:
                payload = jwt.decode(
                    token_key,
                    settings.SECRET_KEY,
                    algorithms=['HS256']
                )
                user_id = payload.get('user_id')
                user = User.objects.get(id=user_id)
                request.user = user
            except (jwt.InvalidTokenError, User.DoesNotExist):
                return JsonResponse(
                    {'error': 'Invalid token'},
                    status=401
                )
        
        response = self.get_response(request)
        return response

Middleware Best Practices

  1. Order matters: Place security middleware first, session before auth, and CSRF after session maintaining proper execution sequence
  2. Keep middleware focused: Each middleware should handle a single concern avoiding complex multi-purpose middleware
  3. Minimize processing: Avoid expensive operations in middleware as they execute for every request impacting performance
  4. Handle exceptions gracefully: Implement proper exception handling preventing middleware from breaking request processing
  5. Use early returns: Short-circuit processing when appropriate avoiding unnecessary view execution
  6. Document dependencies: Clearly document middleware dependencies on other middleware or settings

Conclusion

Django middleware provides powerful infrastructure for implementing application-wide functionality affecting all requests and responses through a clean, modular architecture. Understanding middleware execution order and processing phases enables proper middleware composition avoiding conflicts and ensuring security. Built-in middleware handles essential concerns including security headers, session management, authentication, and CSRF protection. Custom middleware implements application-specific requirements including logging, performance monitoring, custom authentication, throttling, and error handling. Exception handling middleware centralizes error processing providing consistent error responses and notifications. Authentication middleware enables alternative authentication schemes for APIs and specialized access control. Following best practices including proper ordering, focused functionality, minimal processing, graceful exception handling, and clear documentation ensures maintainable middleware implementations. Mastering middleware unlocks capabilities for cross-cutting concerns implementation transforming requests and responses consistently across applications from simple logging to sophisticated security policies throughout Django 6.0 development.

$ cat /comments/ (0)

new_comment.sh

// Email hidden from public

>_

$ cat /comments/

// No comments found. Be the first!

[session] guest@{codershandbook}[timestamp] 2026

Navigation

Connect

Subscribe

// 2026 {Coders Handbook}. EOF.