Middlewares are hooks to modify Django request or response object. Read more about the definition of middleware from Django docs.

You can use middleware if you want to modify the request i.e HttpRequest object which is sent to the view. Or you might want to modify the HttpResponse object returned from the view. Both these can be achieved by using a middleware.

You might want to perform an operation before the view executes. In such case you would use a middleware.

Django provides some default middleware. eg: AuthenticationMiddleware

Very often you would have used request.user inside the view. Django wants user attribute to be set on request before any view executes. Django takes a middleware approach to accomplish this. So Django provides an AuthenticationMiddleware which can modify the request object.

How to create a custom middleware

Django's new-style middleware:

The most important change you need to do when upgrading to Django 2.0 is to change MIDDLEWARE_CLASSES to MIDDLEWARE in settings.py file. In django 2.0 support for old-style middleware using settings.MIDDLEWARE_CLASSES is removed.

The old middleware must be a class where as the new middleware is any callable, which takes a get_response callable and returns a callable that takes the request and returns a response. These middlewares should be specified in MIDDLEWARE setting.

Inside your app create a file middleware.py and paste the following

# middleware.py

class TimeStampMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        request.timestamp = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
        response = self.get_response(request)
        return response


Note: Here the get_response can be either the view that returns the response or the next middleware in the list. Hence the request is processed in the specified order of the middleware and the response in the reverse order.

To activate your custom middleware, you should just add the middleware path in MIDDLEWARE setting.


Django's old-style middleware

Prior to Django 1.10, there were 5 hooks. Any class that implements process_request(), process_view(), process_exception(), process_template_response() and process_response() methods can act as a middleware and all of these are specified in the setting MIDDLEWARE_CLASSES.

The first two methods - process_request(), process_view() are executed before the execution of the view. The next three methods, process_exception(), process_template_response() and process_response() are executed after view returns the response object.

If you want to use the old style, Django provides django.utils.deprecation.MiddlewareMixin which must be extended by the old-style middleware. So that, MiddlewareMixin will convert the class object into a callable.

We can change existing middleware to extend MiddlewareMixin to work in Django 2.0 as follows:

from django.utils.deprecation import MiddlewareMixin

class CustomMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # Process the request

    def process_response(self, request, response):
        # Process the response
        return response

Inheriting from this MiddlewareMixin will make an old-style middleware compatible with the new system.