Django middleware

Django middleware is a hook for modifying Django request or response objects; it can be understood as a processing step between HttpRequest and HttpResponse handling.

During the process from request to response in the browser, Django needs to handle it through many middleware components, as shown in the following figure:

Django middleware purpose:

  • Modify the request, i.e., the HttpRequest object passed to the view.
  • Modifying the response, i.e., the HttpResponse object returned by the view.

Middleware components are configured in the MIDDLEWARE option list in the settings.py file.

Each string option in the configuration is a class, that is, a middleware.

Django's default middleware configuration:

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

Middleware can define four methods, namely:

process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_response(self, request, response)

Steps to customize middleware:

Create a new py file in the app directory with a custom name, and import MiddlewareMixin in that py file:

from django.utils.deprecation import MiddlewareMixin

A custom middleware class must inherit the parent class MiddlewareMixin:

class MD1(MiddlewareMixin): 
    pass
Register the custom middleware class in MIDDLEWARE in settings.py:
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',
   
    'app01.middlewares.MD1',
]

Methods of custom middleware classes

The methods of a custom middleware class include: process_request and process_response.

process_request method

The process_request method has one parameter, request, which is the same as the request in the view function.

The return value of the process_request method can be either None or an HttpResponse object.

  • If the return value is None, continue with the normal flow and pass it to the next middleware for processing.
  • If the return value is an HttpResponse object, Django will not execute the methods before the subsequent view function or the view function itself. Instead, starting from this middleware, it will execute the middleware in reverse order, and only execute the methods that run after the view function.

The process_request method is executed before the view function.

When multiple middleware are configured, they execute in order according to the registration order in MIDDLEWARE, i.e., the list index value.

The request parameter passed between different middleware components is the same request object.

Example

from django.utils.deprecation import MiddlewareMixin

from django.shortcuts import render, HttpResponse

class MD1(MiddlewareMixin):
    def process_request(self, request):
       print("md1 process_request method.", id(request)) # Execute before the view

process_response

The process_response method has two parameters: one is request, and the other is response. request is the request object, and response is the HttpResponse object returned by the view function. This method must have a return value, and it must be response.

The process_response method is executed after the view function.

When multiple middleware are configured, they execute in reverse order according to the registration order in MIDDLEWARE, i.e., the list index value.

Example

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("md1 process_request method.", id(request)) # Execute before the view


    def process_response(self,request, response): :# Based on request/response
        print("md1 process_response method!", id(request)) # After the View
        return response

From the figure below, under normal circumstances execution follows the green route. SupposeMiddleware 1If there is a return value, it follows the red route, directly executes the process_response method of this class and returns; the subsequent other middleware will not be executed.

process_view

The format of the process_view method is as follows:

process_view(request, view_func, view_args, view_kwargs)
The process_view method has four parameters:

  • request is an HttpRequest object.
  • view_func is the view function that Django is about to use.
  • view_args is the list of positional arguments to be passed to the view.
  • view_kwargs is the dictionary of keyword arguments to be passed to the view.

view_args and view_kwargs do not include the first view parameter (request).

The process_view method is executed before the view function and after the process_request method.

The return value can be None, view_func(request), or an HttpResponse object.

  • If the return value is None, continue with the normal flow and pass it to the next middleware for processing.
  • If the return value is an HttpResponse object, Django will not execute the methods before the subsequent view function or the view function itself. Instead, starting from this middleware, it will execute the middleware in reverse order, and only execute the methods that run after the view function.
  • c. If the return value is view_func(request), Django will not execute the methods before subsequent view functions, but will execute the view function in advance, and then execute the methods after the view function in reverse order.
  • After the process_request of the last middleware reaches the route mapping, it returns to the process_view of the first middleware, and then proceeds downward in sequence to reach the view function.

    Example

    class MD1(MiddlewareMixin):
        def process_request(self, request):
            print("md1 process_request method.", id(request)) # Execute before the view


        def process_response(self,request, response): :# Based on request/response
            print("md1 process_response method!", id(request)) # After the View
            return response


        def process_view(self,request, view_func, view_args, view_kwargs):
            print(md1 process_view method!) # Execute before the view; execute sequentially
            #return view_func(request)

    process_exception

    process_exception method is as follows:

    process_exception(request, exception)

    Parameter description:

    • request is an HttpRequest object.
    • exception is the Exception object generated by an exception in the view function.

    The process_exception method is executed only when an exception occurs in the view function, and it executes in reverse order of the registration in settings.

    Executed after the view function and before the process_response method.

    The return value of the process_exception method can be either None or an HttpResponse object.

    If the return value is None, the page will report a 500 status code error, and the view function will not be executed.

    The process_exception method executes in reverse order, and then the process_response method executes in reverse order.

    If the return value is an HttpResponse object, the page will not report an error, and the return status code will be 200.

    The view function is not executed, and the subsequent process_exception methods of this middleware are also not executed. Execution starts directly from the process_response method of the last middleware in reverse order.

    If the process_view method returns the view function and the view function is executed in advance, and the view function reports an error, then regardless of the return value of the process_exception method, the page will report an error, and neither the view function nor the process_exception method will be executed.

    Start executing directly in reverse order from the process_response method of the last middleware:

    Example

    class MD1(MiddlewareMixin):
        def process_request(self, request):
            print("md1 process_request method.", id(request)) # Execute before the view

        def process_response(self,request, response): :# Based on request/response
            print("md1 process_response method!", id(request)) # After the View
            return response

        def process_view(self,request, view_func, view_args, view_kwargs):
            print(md1 process_view method!) # Execute before the view; execute sequentially
            #return view_func(request)


        def process_exception(self, request, exception):# This method is triggered only when an error is raised
            print(md1 process_exception method!)
            # return HttpResponse(exception) # Return error message

    other extensions