Home  >  Article  >  Backend Development  >  What is middleware? Analysis of Django middleware in python

What is middleware? Analysis of Django middleware in python

不言
不言Original
2018-09-25 17:02:483086browse

The content of this article is about what is middleware? The analysis of Django middleware in python has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

What is middleware?

Official statement: Middleware is a framework-level hook used to handle Django requests and responses. It is a lightweight, low-level plug-in system for changing Django's input and output globally. Each middleware component is responsible for doing some specific functions.

But because it affects the global situation, it needs to be used with caution. Improper use will affect performance.

To put it bluntly, middleware helps us do some additional operations before and after the execution of the view function. It is essentially a custom class with several methods defined in the class. Django The framework will execute these methods at the specified time requested.

We have been using middleware, but we just didn’t notice it. Open the Settings.py file of the Django project and see the MIDDLEWARE configuration item in the picture below.

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

MIDDLEWARE configuration item is a list, and the list is a string. These strings are actually classes, that is, middleware.

Then let’s take a look at the methods in middleware and when these methods are executed.

Custom middleware

Middleware can define five methods, namely: (the main ones are process_request and process_response)

  • process_request(self ,request)

  • process_view(self, request, view_func, view_args, view_kwargs)

  • ##process_template_response(self,request,response)

  • process_exception(self, request, exception)

  • process_response(self, request, response)

Above The return value of the method can be None or an HttpResponse object. If it is None, it will continue to execute backwards according to the rules defined by Django. If it is an HttpResponse object, the object will be returned directly to the user.

Customize a middleware example

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response

process_request

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

Its return value can be None or an HttpResponse object. If the return value is None, continue according to the normal process and hand it over to the next middleware for processing. If it is an HttpResponse object, Django will not execute the view function and return the corresponding object to the browser.

Let’s take a look at how Django executes the process_request method when there are multiple middlewares.

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass

Register the above two custom middlewares in the MIDDLEWARE configuration item of 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',
    'middlewares.MD1',  # 自定义中间件MD1
    'middlewares.MD2'  # 自定义中间件MD2
]

At this time, when we visit a view, we will find the following content printed in the terminal:

第一个里面的 process_request
第二个里面的 process_request
app01 中的 index视图

Swap the positions of MD1 and MD2, and then visit a view, we will find the following printed in the terminal The content is as follows:

第二个里面的 process_request
第一个里面的 process_request
app01 中的 index视图

Looking at the results, we know that the view function is executed last, and the second one executes its own process_request method before the first one.

When you print the request parameters in the process_request method in the two custom middlewares, you will find that they are the same object.

To summarize:

  1. The process_request method of middleware is executed before executing the view function.

  2. When configuring multiple middleware, they will be executed in sequence from front to back according to the registration order in MIDDLEWARE, that is, the index value of the list.

  3. The requests passed between different middlewares are all the same object

The process_response method in multiple middlewares is according to MIDDLEWARE The registration order

is executed in reverse order, that is to say, the process_request method of the first middleware is executed first, and its process_response method is executed last. The process_request method of the last middleware is executed last, and its process_response method is Executed first.

process_response

It has two parameters, one is request and the other is response. Request is the same object as in the above example, and response is the HttpResponse object returned by the view function. The return value of this method must also be an HttpResponse object.

Add the process_response method to the above M1 and M2:

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response

Access a view and look at the terminal output:

第二个里面的 process_request
第一个里面的 process_request
app01 中的 index视图
第一个里面的 process_response
第二个里面的 process_response

Look at the results:

## The #process_response method is executed after the view function, and the order is that MD1 is executed before MD2. (At this time, MD2 in settings.py is registered before MD1)

The process_response method in multiple middlewares is executed in accordance with the registration order in MIDDLEWARE

Reverse order

, that is to say, the first one The process_request method of the middleware is executed first, and its process_response method is executed last. The process_request method of the last middleware is executed last, and its process_response method is executed first. process_view

process_view(self, request, view_func, view_args, view_kwargs)

This method has four parameters

request is an HttpRequest object.

view_func is the view function that Django will use soon. (It is the actual function object, not the name of the function as a string.)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

 给MD1和MD2添加process_view方法:

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第二个中的process_view")
        print(view_func, view_func.__name__)

访问index视图函数,看一下输出结果:

第二个里面的 process_request
第一个里面的 process_request
--------------------------------------------------------------------------------
第二个 中的process_view
<function index at 0x000001DE68317488> index
--------------------------------------------------------------------------------
第一个 中的process_view
<function index at 0x000001DE68317488> index
app01 中的 index视图
第一个里面的 process_response
第二个里面的 process_response

process_view方法是在process_request之后,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

process_exception

process_exception(self, request, exception)

该方法两个参数:

一个HttpRequest对象

一个exception是视图函数异常产生的Exception对象。

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

 给MD1和MD2添加上这个方法:

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第一个中的process_exception")
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第二个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第二个 中的process_exception")

如果视图函数中无异常,process_exception方法不执行。

想办法,在视图函数中抛出一个异常:

def index(request):    
print("app01 中的 index视图")    
raise ValueError("呵呵")    
return HttpResponse("O98K")

在MD1的process_exception中返回一个响应对象:

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第一个中的process_exception")
        return HttpResponse(str(exception))  # 返回一个响应对象

看输出结果:

第二个里面的 process_request
第一个里面的 process_request
--------------------------------------------------------------------------------
第二个 中的process_view
<function index at 0x0000022C09727488> index
--------------------------------------------------------------------------------
第一个 中的process_view
<function index at 0x0000022C09727488> index
app01 中的 index视图
呵呵
第一个 中的process_exception
第一个里面的 process_response
第二个里面的 process_response

注意,这里并没有执行MD2的process_exception方法,因为MD1中的process_exception方法直接返回了一个响应对象。

process_template_response(用的比较少)

process_template_response(self, request, response)

它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第一个中的process_exception")
    def process_template_response(self, request, response):
        print("第一个中的process_template_response")
        return response
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第二个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第二个 中的process_exception")
    def process_template_response(self, request, response):
        print("第二个中的process_template_response")
        return response

views.py中:

def index(request):
    print("app01 中的 index视图")
    def render():
        print("in index/render")
        return HttpResponse("O98K")
    rep = HttpResponse("OK")
    rep.render = render
    return rep

访问index视图,终端输出的结果:

第二个里面的 process_request
第一个里面的 process_request
--------------------------------------------------------------------------------
第二个 中的process_view
<function index at 0x000001C111B97488> index
--------------------------------------------------------------------------------
第一个 中的process_view
<function index at 0x000001C111B97488> index
app01 中的 index视图
第一个 中的process_template_response
第二个 中的process_template_response
in index/render
第一个里面的 process_response
第二个里面的 process_response

从结果看出:

视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。

中间件的执行流程

上一部分,我们了解了中间件中的5个方法,它们的参数、返回值以及什么时候执行,现在总结一下中间件的执行流程。

请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。

process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

 

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

附:Django请求流程图

The above is the detailed content of What is middleware? Analysis of Django middleware in python. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Related articles

See more