Django Middlewares: Types and Custom Middleware

Django Middlewares: Types and Custom Middleware

Middleware is a framework of hooks into Django's request/response processing. It is a light plugin system for altering Django’s input or output. Each middleware component is responsible for doing some specific function. You can use middleware if you want to modify the request i.e HttpRequest or you might want to alter the HttpResponse.

How does Django middleware works?

Middleware in Django is a hook or a plugin system for altering request and response objects.

Examples:

  1. Let’s say you want to authenticate a user token in each API call, Some peoples authenticate in every API, but this is not a good way to authenticate, in this case, you can handle the user authentication system in the middleware layer.

  2. Let's say you have two types of users in your application i.e. free and paid. There are few URLs or views that free users cannot access, so in this case either you can handle free users at every view or you can create a middleware that can handle all the free users in one place.

Types of middleware in Django

There are two types of middleware:

  1. Built-in Middlewares

  2. Custom Middlewares

Built-in Middlewares:

  • Security middleware

  • Session middleware

  • Common middleware

  • CSRF protection middleware

  • Authentication middleware

  • Site middleware

  • Cache middleware

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

Custom Middlewares:
These are the middlewares that users can create for their works/purposes.

Description of Middlewares

Authentication Middleware:
It adds the user attribute, representing the currently logged-in user, to every incoming HttpRequest object.

Session Middleware:
It helps you to store arbitrary data on a per-user basis like username, email, etc on the server side.
On every request and response, a session_id is attached to the cookies that you can check in your browser through the console.
Every time a request is made, session middleware gets the stored session data for the particular session_id and attaches it to the request object.

Message Middleware:
Message middleware is used to display some notification message aka flash message to the user after form submission. You can store the message to the request object in your view and then show the message on your front end. You can check out the official documentation for detailed usage.

CSRF Middleware:
CSRF middleware prevents Cross-Site Request Forgery attacks by adding hidden fields like CSRF_TOKEN to the POST forms and later validating for the correct value.

NOTE: Ordering of middleware is very important because middleware depends on other middleware.

Custom Middleware:
Custom Middleware is created either as a function style that takes a get_response callable or a class-based style whose call method is used to process requests and responses. It is created inside a file custom_middleware.py. A middleware is activated by adding it to the MIDDLEWARE list in Django settings.

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',
    # custom middleware
    'todo_app.custom_middleware.CustomMiddleware',
]

Middleware is like a function that takes a request and returns a response.

A middleware can be written in two ways

  1. Function Based

  2. Class Based

The first step is to create a file custom_middleware.py inside your app.

Django Middleware: As a function

You can write this function based middleware code snippet inside custom_middleware.py

def custom_request_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        print("Before response")
        response = get_response(request)
        print("After response")
        # Code to be executed for each request/response after
        # the view is called.
        return response

    return middleware

Django Middleware: As a Class

You can write this class based middleware code snippet inside custom_middleware.py

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

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        print("Before response")
        response = self.get_response(request)
        print("After response")
        # Code to be executed for each request/response after
        # the view is called.

        return response

Activate MIddleware

you have to add it inside the MIDDLEWARE list in settings.py. In the middleware list, each middleware component is represented by a string that is the full python path of the middleware. Add custom middleware at the last of the list.

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

    'todo_app.custom_middleware.CustomRequestMiddleware', # Class based custom Middleware
    'todo_app.custom_middleware.custom_request_middleware', # Function based custom Middleware
]

Now run your server and visit the URL localhost:8000

python manage.py runserver

Now check your terminal for the print statements.

Starting development server at http://0:8080/
Quit the server with CONTROL-C.
Before response
After response

If in terminal print statements are successfully printed, it means you have successfully created your own custom Django middleware.

Now you know how to create custom middleware, Now implement it in your projects and you can use it if your use case needs middleware.

Django Middleware Structure

First of all, middleware is a python class or object that is capable of processing each request and response object. Here is a complete structure of a middleware

class CustomMiddlewareStructure:

    def _init_(self, get_response):
        self.get_response = get_response

    def _call_(self, request):
        # Code that is executed in each request before the view is called

        response = self.get_response(request)
        # Code that is executed in each request after the view is called
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        # This code is executed just before the view is called
        pass

    def process_exception(self, request, exception):
        # This code is executed if an exception is raised
        pass

    def process_template_response(self, request, response):
        # This code is executed if the response contains a render() method
        return response

Let's understand the structure and lifecycle of middleware.

You can also overwrite these methods instead of __call__ method:

  • __init__(get_response)

  • __call__()

  • process_view(request, view_func, view_args, view_kwargs)

  • process_exception(request, exception)

  • process_template_response(request, response)

Let's cover each method one by one.

Method 1: init() in middleware
The first method, init, is the constructor for our Python class. It is called only once, at the time the server starts up. It takes get_response as a parameter, which is passed by Django itself when we add it inside the Middleware list like this: 'todo_app.custom_middleware.CustomSimpleMiddleware'.

Method 2: call() in middleware
__call__() method is called once per request. This method invokes the middleware.
''You can add validation or feature to the request or response object before or after the view is called.''

Method 3: process_view() in middleware
process_view() is called just before Django calls the view.
It should return either None or an HttpResponse object.

  • If it returns None, Django will continue processing this request, executing any other process_view() middleware and, then, the appropriate view.

  • If it returns an HttpResponse object, Django won’t bother calling the appropriate view, it’ll apply response middleware to that HttpResponse and return the result.

Method 4: process_exception() in middleware
Django calls process_exception() when a view raises an exception.
process_exception() should return either None or an HttpResponse object.

  • If it returns an HttpResponse object, the template response and response middleware will be applied and the resulting response returned to the browser.

  • Otherwise, default exception handling kicks in.

Method 5: process_template_response() in middleware
process_template_response() is called just after the view has finished executing if the response instance has a render() method, indicating that it is a TemplateResponse or equivalent.
It must return a response object that implements a render method. It could alter the given response by changing response.template_name and response.context_data, or it could create and return a brand-new TemplateResponse or equivalent.

That's all about middleware. I hope you like it.

Did you find this article valuable?

Support Bharat Phalak by becoming a sponsor. Any amount is appreciated!