中间件
Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。每个中间件都可以完成特定的功能。
中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性,其它的MVC框架也有这个功能,名称为IoC
中间件在哪里?
在settings.py 我们可以看到:
这些字符串,就是一个一个的类。它们就是中间件。
中间件的方法
中间件可以定义五个方法,分别是:(主要的是process_request和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)
以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。
五个方法
1.处理请求前:在每个请求上,request对象产生之后,url匹配之前调用,返回None或HttpResponse对象。
def process_request(self,request):
pass
2.处理视图前:在在每个请求上,url匹配之后,视图函数调用之前调用,返回None或HttpResponse对象。
def process_view(self, request, view_func, view_args, view_kwargs):
pass
3.处理响应后:视图函数调用之后,所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象。
def process_response(self, request, response):
pass
4.处理异常:只有当视图抛出异常时调用,在每个请求上调用,返回一个HttpResponse对象。
def process_exception(self, request, exception):
pass
5.视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。
def process_response(self, request, response):
pass
process_request
process_request有一个参数,就是request,这个request和视图函数中的request是一样的。
它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。
from django.utils.deprecation import MiddlewareMixin class MyMiddle(MiddlewareMixin): def process_request(self, request): print("这是我的第一个中间件-----request----") class MyMiddle2(MiddlewareMixin): def process_request(self, request): print("这是我的第二个中间件-----request----") return
去settings.py注册
结果:
这是我的第一个中间件-----request----
这是我的第二个中间件-----request----
注意:
1 顺序是按中间件注册的顺序执行的。
2 不同中间件之间传递的request都是同一个对象
process_response
它有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。
from django.utils.deprecation import MiddlewareMixin class MyMiddle(MiddlewareMixin): def process_request(self, request): print("这是我的第一个中间件-----request----") def process_response(self, request, response): print("这是我的第一个中间件-----response----") return response # 必须返回的是HttpResponse对象 class MyMiddle2(MiddlewareMixin): def process_request(self, request): print("这是我的第二个中间件-----request----") return def process_response(self, request, response): print("这是我的第二个中间件-----response----") return response
结果:
这是我的第一个中间件-----request---- 这是我的第二个中间件-----request---- 这是视图函数------view------- 这是我的第二个中间件-----response---- 这是我的第一个中间件-----response----
我们可以看到
(1)它是在执行视图函数之后
(2)注意它的执行顺序:倒序执行。也就是与注册中间件的顺序相反。
process_view
process_view(self, request, view_func, view_args, view_kwargs)
该方法有四个参数
request是HttpRequest对象。
view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
view_args是将传递给视图的位置参数的列表.
view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。
Django会在调用视图函数之前调用process_view方法。
它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。
如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
from django.utils.deprecation import MiddlewareMixin class MyMiddle(MiddlewareMixin): def process_request(self, request): print("这是我的第一个中间件-----request----") def process_response(self, request, response): print("这是我的第一个中间件-----response----") return response def process_view(self, request, view_func, view_args, view_kwargs): """ :param request: 浏览器发来的请求对象 :param view_func: 将要执行的视图函数的名字 :param view_args: 将要执行的视图函数的位置参数 :param view_kwargs: 将要执行的视图函数的关键字参数 :return: """ print("这是我的第一个中间件----process_view-----") print(view_func) class MyMiddle2(MiddlewareMixin): def process_request(self, request): print("这是我的第二个中间件-----request----") return def process_response(self, request, response): print("这是我的第二个中间件-----response----") return response def process_view(self, request, view_func, view_args, view_kwargs): print("这是我的第二个中间件----process_view-----") print(view_func)
结果:
这是我的第一个中间件-----request---- 这是我的第二个中间件-----request---- 这是我的第一个中间件----process_view----- <function index at 0x000001B7CF806BF8> 这是我的第二个中间件----process_view----- <function index at 0x000001B7CF806BF8> 这是视图函数------view------- 这是我的第二个中间件-----response---- 这是我的第一个中间件-----response----
我们可以看到:
(1)它的执行顺序与注册中间件的顺序一致,从上到下。
(2)在执行视图函数之前
process_exception
process_exception(self, request, exception)
该方法两个参数:
一个HttpRequest对象
一个exception是视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,
并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
from django.utils.deprecation import MiddlewareMixin class MyMiddle(MiddlewareMixin): def process_request(self, request): print("这是我的第一个中间件-----request----") def process_response(self, request, response): print("这是我的第一个中间件-----response----") return response def process_view(self, request, view_func, view_args, view_kwargs): print("这是我的第一个中间件----process_view-----") print(view_func) # 只有视图函数异常才会执行 def process_exception(self, request, exception): print(exception) print("第一个中间件 中的process_exception") class MyMiddle2(MiddlewareMixin): def process_request(self, request): print("这是我的第二个中间件-----request----") return def process_response(self, request, response): print("这是我的第二个中间件-----response----") return response def process_view(self, request, view_func, view_args, view_kwargs): print("这是我的第二个中间件----process_view-----") print(view_func) def process_exception(self, request, exception): print(exception) print("第二个中间件 中的process_exception")
结果:
这是我的第一个中间件-----request---- Traceback (most recent call last): 这是我的第二个中间件-----request---- 这是我的第一个中间件----process_view----- <function index at 0x000001BEB3206BF8> 这是我的第二个中间件----process_view----- <function index at 0x000001BEB3206BF8> 这是视图函数------view------- ---------------------------------------------- 第二个中间件 中的process_exception 第一个中间件 中的process_exception ---------------------------------------------- 这是我的第二个中间件-----response---- 这是我的第一个中间件-----response----
可以看到:
(1)执行顺序是倒序
(2)在执行视图函数之后,返回响应之前
中间的执行过程
请求到达中间件之后,先按照正序执行每个注册中间件的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两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下: