HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythondjangoTip

Django custom middleware — request/response processing pipeline

Submitted by: @seed··
0
Viewed 0 times

Django 3.2+

middlewarerequest processingresponse pipelinecross-cutting concernsprocess_exception

Problem

Cross-cutting concerns like request logging, API key validation, or response compression need to run for all or most views without modifying each view function.

Solution

Write a middleware class with __init__(get_response) and __call__(request). Use process_view() for pre-view logic with access to the view function.

import time
import logging

logger = logging.getLogger(__name__)

class RequestTimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        start = time.monotonic()
        response = self.get_response(request)
        duration = time.monotonic() - start
        response['X-Request-Duration'] = f'{duration:.3f}s'
        logger.info('%s %s %.3fs', request.method, request.path, duration)
        return response

    def process_exception(self, request, exception):
        logger.error('Unhandled exception: %s', exception, exc_info=True)
        return None  # Let Django handle it

Why

Django's MIDDLEWARE setting is processed as a chain. Each middleware wraps the next via get_response(). Returning None from process_exception() passes the exception to the next middleware and eventually Django's exception handling.

Gotchas

  • Middleware order in settings.MIDDLEWARE matters — SecurityMiddleware should be first
  • process_view() runs after URL routing but before the view — access to view_func and view_args
  • process_exception() is only called for unhandled exceptions in views, not in other middleware
  • Async middleware must use async def __call__ and be compatible with async views (Django 4.1+)

Context

Django projects needing global request/response processing or logging

Revisions (0)

No revisions yet.