Django Middleware
Django middleware is a hook that modifies Django request or response objects, acting as a processing step between HttpRequest and HttpResponse handling.
Throughout the process from request to response in the browser, Django needs to go through many middleware layers, as illustrated in the following diagram:
Django Middleware Functions:
- Modify requests, i.e., the HttpRequest object sent to the view.
- Modify responses, i.e., the HttpResponse object returned by the view.
Middleware components are configured in the MIDDLEWARE option list in the settings.py file.
Default Django 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:
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 Create Custom Middleware:
Create a new Python file in the app directory with a custom name and import MiddlewareMixin in that file:
from django.utils.deprecation import MiddlewareMixin
The custom middleware class should inherit from the MiddlewareMixin class:
class MD1(MiddlewareMixin):
pass
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 in Custom Middleware Classes
Custom middleware classes include methods like process_request and process_response.
process_request Method
The process_request method has a parameter request, which is the same as the request in the view function.
The return value of process_request can be None or an HttpResponse object.
- If the return value is None, the process continues normally, passing to the next middleware.
- If the return value is an HttpResponse object, Django will not execute methods before the view function or the view function itself. Instead, it will start from this middleware, executing the methods after the view function in reverse order.
The process_request method is executed before the view function.
When multiple middleware are configured, they are executed in the order they are registered in the MIDDLEWARE list, based on their index values.
The request parameter passed between different middleware 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)) # Executed before the view
### process_response
process_response method has two parameters: request and response. request is the request object, and response is the HttpResponse object returned by the view function. This method must return a value, which must be response.
process_response method is executed after the view function.
When multiple middleware are configured, they are executed in reverse order according to the registration order in MIDDLEWARE, i.e., the index values of the list.
## Example
<pre><code>class MD1(MiddlewareMixin):
def process_request(self, request):
print("md1 process_request method.", id(request)) # Executed before the view
def process_response(self, request, response): # Based on request-response
print("md1 process_response method!", id(request)) # Executed after the view
return response
</code></pre>
From the diagram below, under normal circumstances, execution follows the green path. If **Middleware 1** has a return value, it follows the red path, directly executing the process_response method of this class and returning, without executing subsequent middleware.
### process_view
process_view method format is as follows:
<pre><code>process_view(request, view_func, view_args, view_kwargs)
</code></pre>
- request is the HttpRequest object.
- view_func is the view function that Django is about to use.
- view_args is a list of positional arguments to be passed to the view.
- view_kwargs is a dictionary of keyword arguments to be passed to the view.
Neither view_args nor view_kwargs include the first view argument (request).
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 process and hand over to the next middleware.
- If the return value is an HttpResponse object, Django will not execute the methods before the subsequent view function and the view function itself. Instead, it will start from this middleware, execute in reverse order, and execute the methods after the view function.
- If the return value is view_func(request), Django will not execute the methods before the subsequent view function, but will execute the view function early, and then execute the methods after the view function in reverse order.
When the process_request of the last middleware reaches the routing relationship mapping, it returns to the first middleware's process_view, then proceeds downwards to the view function.
## Example
<pre><code>class MD1(MiddlewareMixin):
def process_request(self, request):
print("md1 process_request method.", id(request)) # Executed before the view
def process_response(self, request, response): # Based on request-response
print("md1 process_response method!", id(request)) # Executed after the view
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("md1 process_view method!") # Executed before the view, sequentially
# return view_func(request)
</code></pre>
### process_exception
process_exception method is as follows:
<pre><code>process_exception(request, exception)
</code></pre>
Parameter description:
- request is an HttpRequest object.
- exception is an Exception object generated by the view function.
- The process_exception method is only executed when an exception occurs in the view function, and it executes in reverse order of registration according to settings.
- It is 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 show a 500 status code error, and the view function will not execute.
- The process_exception method executes in reverse order, followed by the process_response method in reverse order.
- If the return value is an HttpResponse object, the page will not show an error, and the status code will be 200.
- If the view function does not execute, subsequent process_exception methods of the middleware will not execute either, and execution will start in reverse order from the process_response method of the last middleware.
- If the process_view method returns the view function, and the view function executes prematurely and throws an error, the page will show an error regardless of the return value of the process_exception method, and neither the view function nor the process_exception method will execute.
- Execution starts 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)) # Executed before the view
def process_response(self, request, response): # Based on request-response
print("md1 process_response method!", id(request)) # Executed after the view
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("md1 process_view method!") # Executed before the view, in order
# return view_func(request)
def process_exception(self, request, exception): # Triggered only if an error occurs
print("md1 process_exception method!")
# return HttpResponse(exception) # Returns error information
```