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', # 定义了2个自定义的中间件 'middle.md.middle_first', 'middle.md.middle_second' ]
#Auther Bob #--*--conding:utf-8 --*-- from django.utils.deprecation import MiddlewareMixin import time from django.shortcuts import HttpResponse # 中间件就是一个类,下面咱们自定义了2个中间件,中间件又叫作管道 class middle_first(MiddlewareMixin): def process_request(self,request): print("middle_first--process_request",time.time()) return HttpResponse("大爷慢走") def process_response(self,request,response): print("middle_first--process_response", time.time()) print(response, type(response)) return response class middle_second(MiddlewareMixin): def process_request(self,request): print("middle_second--process_request",time.time()) def process_response(self,request,response): print("middle_second--process_response", time.time()) print(response,type(response)) return response
def process_request(self,request): path = request.path_info # l = path.split("/") # if l[2] in black_list: # return HttpResponse("不能访问") re_compile_obj = re.compile("/") l = re_compile_obj.split(path) for i in l: if i in black_list: return HttpResponse("不能访问")
在看process_response方法,参数必需要要有个response,这个参数必需要有,并且这个process_response的函数必需要有返回值,若是没有,django会把报错的,最后一个中间件的process_response把返回值返回给倒数第一个中间件的process_response函数,而后在返回倒数第三个中间件的process_response函数,这个参数默认就是视图函数的返回,咱们也能够自定义返回值,下面的例子就是咱们自定义返回值,process_response是按照注册顺序的倒序执行html
def process_response(self,request,response): print("--------->","这个是response的中间件") return HttpResponse("中间件直接返回的")
结果以下前端
咱们还使用默认的response的返回值,也就是用视图函数的返回值python
def process_response(self,request,response): print("--------->","这个是response的中间件") # return HttpResponse("中间件直接返回的") return response
结果以下django
process_view函数,多个中间件的process_view函数是按照注册的正序执行,在执行视图函数以前执行,若是有返回值,则不会执行视图函数的方法,执行返回执行process_response函数,若是没有返回值,则会执行完process_view后在执行视图函数session
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-------->") return HttpResponse("process_view返回值")
上面的例子的process_view函数有返回值,咱们看下结果,能够看到返回的process_view函数的返回值,没有去执行视图函数app
下面这个例子,process_view函数中没有返回值函数
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-------->") # return HttpResponse("process_view返回值")
结果以下,咱们看到返回的是视图的返回值post
在看下process_exception的中间件的函数学习
def process_exception(self,request,exception): """ :param request: 这个是请求对象 :param exception: 这个是视图函数返回的错误 :return: """ print(exception) print("这个是中间件exception函数") return redirect("https://www.baidu.com")
他的执行顺序是按照在中间件注册的倒序执行的,若是视图函出错,才会执行,下面咱们模拟视图函数出错,用raise方法主动抛出错误测试
def test_forms(request): print(request.path_info) # for i in range(10): # models.City.objects.create( # name = "北京" + str(i) # ) print(models.City.objects.all().values("name")) if request.method.lower() == "post": myform = Myform(request.POST) # 把post方式传递过来的数据传递个myform对象 if myform.is_valid(): # 对前端发过来的数据作校验,若是合法的话 name = myform.cleaned_data.get("name") pwd = myform.cleaned_data.get("pwd") rep_pwd = myform.cleaned_data.get("rep_pwd") print(myform.cleaned_data) else: pass else: myform = Myform() raise ValueError("视图函数执行失败了") return render(request,"form1.html",{"myform":myform})
看下打印的信息
视图函数执行失败了
这个是中间件exception函数
---------> 这个是response的中间件
先看下中间件在django整个流程处于哪一个阶段
中间件的执行顺序是这样的
按照settings里面MIDDLEWARE的列表中的顺序来执行,先执行第一个中间件的process_request方法,而后执行第二个中间件的process_request方法,直到最后一个中间件的process_request方法,执行完成以后,就到views中的视图函数,而后返回的时候在从最后一个中间件的process_response方法,而后执行倒数第二个process_response方法,一直都第一个中间件的process_response方法
这里咱们须要注意,中间件的函数中的request参数,和视图函数中的request参数是同样的,response参数,就是视图函数中return返回的值
咱们先看下执行顺序
首先咱们在middleware中定义的中间件的顺序是这样的
# 定义了2个自定义的中间件 'middle.md.test', 'middle.md.middle_first', 'middle.md.middle_second'
咱们在看先咱们的中间件函数
from django.utils.deprecation import MiddlewareMixin import time from django.shortcuts import HttpResponse # 中间件就是一个类,下面咱们自定义了2个中间件,中间件又叫作管道 class test(MiddlewareMixin): def process_request(self,request): print("test--process_request", time.time()) def process_response(self,request,response): print("test--process_response", time.time()) return response class middle_first(MiddlewareMixin): def process_request(self,request): print("middle_first--process_request",time.time()) # return HttpResponse("大爷慢走") def process_response(self,request,response): print("middle_first--process_response", time.time()) # print(response, type(response)) return response class middle_second(MiddlewareMixin): def process_request(self,request): print("middle_second--process_request",time.time()) def process_response(self,request,response): print("middle_second--process_response", time.time()) # print(response,type(response)) return response
这里咱们要注意,在咱们定义的3个中间件的类中,process_request方法中都没有return,咱们从客户端发起请求,看下中间件函数的执行顺序,和咱们上面分析的是同样的
下面咱们在在middle_first类中的process_request方法中定义一个return,在看下执行顺序
咱们再次经过客户端去访问
咱们在看下执行顺序
先执行test的process_request方法,而后执行middle_first的process_request方法,由于这里的方法中咱们有定义return,因此就不会在往下执行,直接走middle_first的process_response方法,而后执行test的process_response方法
如今咱们对中间件的执行顺序应该已经比较清楚了吧
下面咱们经过源代码来分析一下中间件
首先咱们先看下类中定义的__call__方法,这个方法何时会执行呢?
前面我忘记了,后来测试了一下,如今知道了,咱们在回忆一下
class test_call(object): def __init__(self,call): self.call = call def __call__(self, *args, **kwargs): print("如今是执行{call}".format(call = self.call)) if __name__ == '__main__': t = test_call("cui") t()
执行结果
因此__call__方法是在执行类的对象的时候会调用__call__方法
咱们看到咱们定义的中间件的类都继承了MiddlewareMixin这个类,咱们来看下这个类是怎么写的
class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response
咱们重点看下看这里
首先定义response为空,由于中间件的执行顺序是先执行process_request方法,咱们这里经过反射的hasattr方法,先来判断是否有定义process_request方法,若是有定义,则执行,执行process_request方法,若是这个方法有返回值,那么就不会执行第二个if中的代码,第二个if中的代码咱们后面在说他的意思,若是,有process_request方法,且有返回值,则会执行第三个if中的方法,就会执行这个中间的process_response方法,这样就和咱们上面的例子对应上了;
下面咱们来讲一下第二个if中的代码的做用,他的做用就是执行下一个中间件函数的__call__方法,若是没有下一个中间件,则会执行视图函数中对应的方法
咱们推荐你们这样写,本身实现写middlewareMixin类,而后咱们本身的中间件类继承咱们本身写的middlewareMixin类就能够了
from django.utils.deprecation import MiddlewareMixin import time from django.shortcuts import HttpResponse class my_MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(my_MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response # 中间件就是一个类,下面咱们自定义了2个中间件,中间件又叫作管道 class test(my_MiddlewareMixin): def process_request(self,request): print("test--process_request", time.time()) def process_response(self,request,response): print("test--process_response", time.time()) return response class middle_first(my_MiddlewareMixin): def process_request(self,request): print("middle_first--process_request",time.time()) return HttpResponse("大爷慢走") def process_response(self,request,response): print("middle_first--process_response", time.time()) # print(response, type(response)) return response class middle_second(my_MiddlewareMixin): def process_request(self,request): print("middle_second--process_request",time.time()) def process_response(self,request,response): print("middle_second--process_response", time.time()) # print(response,type(response)) return response
class test(my_MiddlewareMixin): def process_request(self,request): print("test--process_request", time.time()) def process_view(self,request,view_func,view_args,view_kwargs): print(view_func, view_args, view_kwargs, sep="-------->") print("test--process_view", time.time()) def process_response(self,request,response): print("test--process_response", time.time()) return response def process_exception(self,request,exception): """ :param request: :param exception: 只能捕获视图函数中的异常捕获,对中间件中的其余函数的错误是捕获不到的,这里的excetion就是错误的信息 :return: """ print("test--process_exception", time.time())
若是视图函数中不出错的话,process_exception是永远都不会执行的,好比下面一个正常的访问流程,咱们访问的test函数没有出错,按照顺序执行,先执行第一个中间件的process_request方法,而后是第二个中间件的process_request方法,而后是第三个中间件的process_request方法,而后执行第一个中间件的process_view方法,而后是第二个中间件的process_view方法,而后是第三个中间件的process_view方法,而后执行视图函数,在返回的时候,先执行最后一个中间件的process_response方法,而后是倒数第二个process_view方法,而后是倒数第三个中间件的processs_response方法
下面咱们看下如何视图函数中有错误的话,会如何执行
咱们首先在视图函数中构建了一个错误
def test(request): int("hahah") print("test------->views",time.time()) return HttpResponse("last_app1")
再次经过客户端去访问,咱们在第二个中间件的process_exception方法中作了return返回
执行顺序是下面这样的
先执行第一个中间件的process_request方法,而后是第二个中间件的process_request方法,最后是第三个中间件的process_request方法,而后执行第一个中间件的process_view方法,而后是第二个中间件的process_view方法,最后是执行第三个中间件的process_view方法,这里很关键,由于咱们执行视图函数报错,由于咱们人为构建了一个错误,开始执行最后一个中间件的process_exception方法,执行完成后,执行倒数第二个中间件的process_exception方法,执行到这里,这个函数有个return返回值,那么就不会在去执行第一个中间件的process_exception的方法了,这个时候就开始执行最后一个中间件的process_response方法,而后是倒数第二个中间件的process_exception方法,最后是倒数第三个中间件的process_response方法
补一个中间件的小例子,就是黑名单的意思,若是访问的是某个url则直接给返回
下面看下代码
from django.middleware.security import SecurityMiddleware from django.utils.deprecation import MiddlewareMixin import re from django.shortcuts import HttpResponse from django.shortcuts import render from django.shortcuts import redirect black_list = ["publish","add_publish"] class My_first_mid(MiddlewareMixin): def process_request(self,request): path = request.path_info # l = path.split("/") # if l[2] in black_list: # return HttpResponse("不能访问") re_compile_obj = re.compile("/") l = re_compile_obj.split(path) for i in l: if i in black_list: return HttpResponse("不能访问")
前端访问的效果
首先是能够访问
而后是不能访问
中间件的定义: wsgi以后 urls.py以前 在全局 操做Django请求和响应的模块! 中间件的使用: 5个固定的方法 process_request(self, request) 执行顺序: 按照注册的顺序(在settings.py里面设置中 从上到下的顺序) 什么时候执行: 请求从wsgi拿到以后 返回值: 返回None,继续执行后续的中间件的process_request方法 返回response , 不执行后续的中间件的process_request方法 process_response 执行顺序: 按照注册顺序的倒序(在settings.py里面设置中 从下到上的顺序) 什么时候执行: 请求有响应的时候 返回值: 必须返回一个response对象 process_view(self, request, view_func, view_args, view_kwargs): 执行顺序: 按照注册的顺序(在settings.py里面设置中 从上到下的顺序) 什么时候执行: 在urls.py中找到对应关系以后 在执行真正的视图函数以前 返回值: 返回None,继续执行后续的中间件的process_view方法 返回response, process_exception(self, request, exception) 执行顺序: 按照注册顺序的倒序(在settings.py里面设置中 从下到上的顺序) 什么时候执行: 视图函数中抛出异常的时候才执行 返回值: 返回None,继续执行后续中间件的process_exception 返回response, process_template_response(self, request, response) 执行顺序: 按照注册顺序的倒序(在settings.py里面设置中 从下到上的顺序) 什么时候执行: 视图函数执行完,在执行视图函数返回的响应对象的render方法以前 返回值: 返回None,继续执行后续中间件的process_exception 返回response, Django调用 注册的中间件里面五个方法的顺序: 1. process_request urls.py 2. process_view view 3. 有异常就执行 process_exception 4. 若是视图函数返回的响应对象有render方法,就执行process_template_response 5. process_response