BudiBadu Logo
Samplebadu

Django by Example: Middleware Request Hooks

Django 5.0+

Middleware is a framework of hooks into Django's request/response processing. This sample code demonstrates a light, low-level "plugin" system for globally altering Django's input or output.

Code

import time

class SimpleTimingMiddleware:
    def __init__(self, get_response):
        # One-time configuration and initialization.
        self.get_response = get_response

    def __call__(self, request):
        # 1. Code to be executed for each request BEFORE
        # the view (and later middleware) are called.
        start_time = time.time()
        print(f"Request started: {request.path}")

        # Call the next middleware or the view
        response = self.get_response(request)

        # 2. Code to be executed for each request/response AFTER
        # the view is called.
        duration = time.time() - start_time
        
        # Add a custom header to the response
        response['X-Page-Generation-Duration-ms'] = int(duration * 1000)
        
        print(f"Request finished. Duration: {duration:.4f}s")

        return response

    def process_exception(self, request, exception):
        # Optional: Called if the view raises an exception
        print(f"Something went wrong: {exception}")
        return None # Let standard error handling continue

Explanation

Middleware is a framework of hooks into Django's request/response processing. It's a light, low-level "plugin" system for globally altering Django's input or output. Middleware is initialized once when the server starts (via __init__) and then called for every request.

The __call__ method is the heart of the middleware. Code before get_response(request) runs on the way "in" (request processing), and code after it runs on the way "out" (response processing). You can also define specific hooks:

  • process_view: Executed just before the view is called. Useful for pre-view validation.
  • process_exception: Executed only if the view raises an exception. Ideal for custom error logging or reporting.
  • process_template_response: Executed for template responses, allowing you to modify the context data before rendering.

The order of middleware in settings.MIDDLEWARE is critical. It forms an "onion" structure: the first middleware defined is the first to see the request and the last to see the response. This is why security middleware is usually placed at the top, while compression middleware is placed near the bottom.

Code Breakdown

4
__init__. Receives get_response, which is a callable representing the next middleware in the chain (or the actual view). You must store this.
8
__call__. This makes the class instance callable. This method is the heart of the middleware, running for every single request.
15
response = self.get_response(request). This line divides the "Before View" logic from the "After View" logic. It passes control down the chain.
22
Modifying the response. Here we add a custom HTTP header X-Page-Generation-Duration-ms. This is a common pattern for performance monitoring tools.