Django Custom Middleware

Django middleware is a way to globally alter requests and responses ie. middlewares are layers of business logic that will be applied to all requests and responses. Consider an example to add logging for all requests, then the ideal way would be to add a middleware layer for the same, another example would be adding a common header to all the responses and again middleware is the best place to add this.

As per Django documentation:

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.

Technically speaking, Middleware is a normal Python class that should have at least one of these methods defined.

  • process_request
  • process_view
  • process_exception
  • process_template_response
  • process_response

Please note that middlewares are not exclusive to Django, it is a concept that is applicable to any request-response cycle written in any language/framework.

Where can I find middleware in my Django project?

In Django, you can see all the default installed middlewares in the settings.py module. Please do not remove any, unless you know what you are doing.

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',
]

Does ordering matter in middlewares?

Yes, ordering of layers matters in middlewares, as logic written in a layer below, can expect something added from the layers above. Let's understand this with an example if AuthenticationMiddleware is present before SessionMiddleware, it will raise AssertionError because AuthenticationMiddleware expects request object to have session attribute, which is added by SessionMiddleware.

class AuthenticationMiddleware(object):
    def process_request(self, request):
        assert hasattr(request, 'session'), (
            "The Django authentication middleware requires session middleware "
            "to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
            "'django.contrib.sessions.middleware.SessionMiddleware' before "
            "'django.contrib.auth.middleware.AuthenticationMiddleware'."
        )
        request.user = SimpleLazyObject(lambda: get_user(request))
AuthenticationMidddleware expects request has session attribute.

The Middleware classes are called twice during the request/response life cycle, during the request cycle, the middleware classes are executed top-down, while during the response, middleware classes are called in a bottom-up manner.

Ordering matters in middlewares
Middleware | Django documentation | Django

Custom Middleware

Let's add a custom middleware to our Django project which logs the total time taken by the view. In order to install a middleware, we need to put it in settings.py

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',    
    ...
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'common.middleware.LogTimeTaken',
]
from django.utils import timezone


class LogTimeTaken(object):

    def process_request(self, request):
        request.start_time = timezone.now()

    def process_response(self, request, response):
        total_time = timezone.now() - request.start_time
        print('Time taken: {}'.format(total_time))

Conclusion:

  • Middlewares as a concept is a way to globally alter request-response behavior and is not exclusive to Django.
  • In Django specifically, middlewares are normal Python classes with certain methods. These classes are called twice during the request/response life cycle, top-down while in the request phase, and reverse during in response.
  • Ordering matters, as a middleware can depend on other middleware during its execution.

References:

Middleware | Django documentation | Django