[Django advanced] Understand the middleware mechanism and execution sequence in django, and django Middleware
The original Article is from Understanding Django Middlewares. This article introduces the definition and function of middleware in django and how to write the middleware-orangleliu by yourself.
Note: The meaning of middleware and middleware is the same in the following article, but they are not completely translated.
Suppose you have read middleware in the Django official document. The following describes the Knowledge mentioned in the document as much as possible, but I hope you will be familiar with it.middleware
Basic concepts.
In this article, we will discuss the following content:
- What is middleware?
- When to use middleware
- What we need to remember when writing middleware
- Write some middlewares to understand the working process and key points of the middleware.
What is middleware?
Middlewares is used to modify DjangoRequestOrResponseObject hook. Below is a description in the Django document.
Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.
When to use middleware
If you want to modify the request, for exampleHttpRequestObject. Or you want to modifyHttpResponseObjects, which can be implemented through middleware.
You may want to perform some operations before the view execution. In this case, you can use middleware to implement the operation.
Django provides some default middleware, such:
AuthenticationMiddleware
Users may frequently use the view.request.user
Right. Django wants to set the user as the request Attribute before each view is executed, so a middleware is used to achieve this goal. Therefore, Django provides middleware that can modify the request object.AuthenticationMiddleware
.
Django modifies the request object as follows:
https://github.com/django/django/blob/master/django/contrib/auth/middleware.py#L22
For example, if you have an application, its users are people in different time zones. You want them to display the correct time zone when accessing any page, and want all views to get their own timezone information. In this case, you can use the session to solve the problem, so you can add a middleware as follows:
class TimezoneMiddleware(object): def process_request(self, request): # Assuming user has a OneToOneField to a model called Profile # And Profile stores the timezone of the User. request.session['timezone'] = request.user.profile.timezone
TimezoneMiddleware depends on request. user, and request. userAuthenticationMiddleware
. Therefore
settings.MIDDLEWARE_CLASSES
In configuration, TimezoneMiddleware must be later than AuthenticationMiddleware.
The following example shows more about the middleware sequence.
What should be remembered when Using middleware
- The order of middlewares is very important.
- A middleware only needs to inherit the object class
- One middleware can implement some methods without implementing all the methods.
- One middleware can implementProcess_request (method)But cannot be implementedProcess_response (method)And process_view. These are common. Django provides many middlewares.
- One middleware can implementProcess_responseMethod, but does not need to be implementedProcess_requestMethod
AuthenticationMiddleware only processes the request and does not process the response.
GZipMiddleware only processes the response and does not process the request and view. For more information, see the document.
Write some middlewares
First, make sure that you have a Django project that requires a url and a view, and you can enter this view. Next we will perform a few tests on request. user, confirm that the permission is set, and correctly print the request. user information in the view.
Create the middleware. py file in any app.
I have an app called books, so the file location isbooks/middleware.py
class BookMiddleware(object): def process_request(self, request): print "Middleware executed"
Add this middleware to MIDDLEWARE_CLASSES
MIDDLEWARE_CLASSES = ( 'books.middleware.BookMiddleware', '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',)
Send a request to any url. The following information is printed on the runserver console.
Middleware executed
ModifyBookMiddleware.process_request
As follows:
class BookMiddleware(object): def process_request(self, request): print "Middleware executed" print request.user
Accessing a url again will cause an error.
'WSGIRequest' object has no attribute 'user'
This is because the user attribute has not been set for the request object.
Now let's change the order of middlewares,BookMiddleware
Put inAuthenticationMiddleware
Later.
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'books.middleware.BookMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',)
Access a url. The following figure is printed on the runserver console:
Middleware executed<username>
This indicates that the order in which middlewares processes requests is the same as that listed in settings. MIDDLEWARE_CLASSES.
You can further confirm that middleware. py adds another middleware
class AnotherMiddleware(object): def process_request(self, request): print "Another middleware executed"
Add itMIDDLEWARE_CLASSES
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'books.middleware.BookMiddleware', 'books.middleware.AnotherMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',)
The output is as follows:
Middleware executed<username>Another middleware executed
In the process_request method, return HttpResponse and change BookMiddleware to the following:
class BookMiddleware(object): def process_request(self, request): print "Middleware executed" print request.user return HttpResponse("some response")
Try any url and get the following output:
Middleware executed<username>
You will notice the following two things:
- No matter which url you access, the view processing method you write is not executed, and there is only a response like "some response.
- AnotherMiddleware. process_request is not executed
Therefore, if the HttpResponse object is returned in the process_request method of Middleware, the later Middleware will be skipped and the processing method in the view will also be skipped.
Therefore, this is rarely done in actual projects (but some projects, such as proxies)
Comment out"return HttpResponse("some response")"
, And both middleware can process requests normally.
Use process_response
Add the process_response Method to the two middleware instances.
class AnotherMiddleware(object): def process_request(self, request): print "Another middleware executed" def process_response(self, request, response): print "AnotherMiddleware process_response executed" return responseclass BookMiddleware(object): def process_request(self, request): print "Middleware executed" print request.user return HttpResponse("some response") #self._start = time.time() def process_response(self, request, response): print "BookMiddleware process_response executed" return response
Access some URLs to get the following output:
Middleware executed<username>Another middleware executedAnotherMiddleware process_response executedBookMiddleware process_response executed
AnotherMiddleware.process_response()
InBookMiddleware.process_response()
Previously executedAnotherMiddleware.process_request()
InBookMiddleware.process_request()
Then execute.process_response()
The execution sequence is the opposite of process_request.process_response()
The execution sequence is from the last middleware to the last, until the first middleware.
Process_view
Django executes middleware in orderprocess_view()
From top to bottom. Similar to the order in which process_request () is executed.
So if anyprocess_view()
If the HttpResponse object is returnedprocess_view()
Will be omitted and will not be executed.