How To Create a Custom Middleware with Django

Vincent Lossel
3 min readAug 2, 2023

--

What is a middleware?

A middleware is a class (or function) integrated into the request/response lifecycle in a Django application. Middlewares are called twice in the life cycle of the application: for requests, before carrying out the routing and the call of the views; for responses, before returning the response to the web server. Each request/response will be processed by all the middlewares in the order provided by the project.

Middlewares make it possible to add certain functionalities and to carry out operations on the requests/responses before continuing their journey. It is a very efficient and very flexible tool.

By default, Django integrates several middlewares allowing to ensure the authentication of the request, the respect of certain security mechanisms (CSRF, XSS…) or even the increase of the response with specific features (internationalization, messages...).

Why use a custom middleware?

There are many reasons for adding custom middleware. They offer great flexibility for adding specific features to your application, without any particular complexity.

For example, a personalized middleware can make it possible to add request pre-processing operations, to check requests parameters, to record statistics, to improve error management or even to connect to an external API…

Adding a custom middleware

Each middleware must be listed in the project configuration under MIDDLEWARE_CLASSES. Middlewares can be stored anywhere in the project.

MIDDLEWARE_CLASSES = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.auth.middleware.SessionAuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]

The order of the middlewares is important since it is the order in which they will be called for each request. Each middleware needs to return the request after performing its operations, to pass it to the next middleware.
For example, this means that the user will not be accessible in the request until it has been processed by the middleware in charge of authentication. The positioning of your middleware in this list must therefore be based on the elements of the request which must be accessible to your middleware and/or which must be accessible to other middleware.

When the last middleware is called, the request will be able to continue its progression through the application lifecycle.

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

def __call__(self, request):
# Preparation ops

# Retrieving the response
response = self.get_response(request)

# Updating the response

# Returning the response
return response

The __init__(self, get_response) method is called only once when the application is launched. This method is used to configure and initialize the middleware, in order to ensure its proper functioning thereafter. In this case, it is used to retrieve the response that will be returned after each request. It can be the view or the template to return.

The __call__(self, request) method is called for each request/response received by the application. This method should return a response that will be passed to the next middleware or to the view if it was the last middleware in the list. It is in this method that you can carry out all your operations.

Older versions of Django also provided several methods specific to each type of response: process_view, process_template_response, process_exception
In each middleware and for each response, Django will activate each of these methods. These methods are still present in Django for compatibility with older projects, but have been deprecated. To use the old style and the different methods, it is necessary to inherit your middleware from the MiddlewareMixin(from django.utils.deprecation.MiddlewareMixin).

--

--

No responses yet