Django(中间件)
一.中间件介绍
中间件是介于request与response处理之间的一道处理过程 直白一点中间件是视图函数执行之前和执行之后都可以做一些额外的操作
settings.py中的MIDDLEWARE列表中存放的就是中间件
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', ]
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import redirect,reverse,HttpResponse class MD1(MiddlewareMixin): white_list = ["/login/", "register", ] def process_request(self, request): #没有返回值,或返回值为None if request.path not in self.white_list: request.username = request.session.get('username') #将username封装到request中,在其他函数中可直接使用request.username if not request.username: return redirect('/login/') #login函数中设置session def login(req): if req.method == "GET": user_objs = myforms.LoginForms() return render(req, "base/login.html", {"user_objs":user_objs}) else: user_objs = myforms.LoginForms(req.POST) if user_objs.is_valid(): req.session["username"] = user_objs.cleaned_data["username"] req.session["password"] = user_objs.cleaned_data["password"] return redirect("/base/") else: return render(req, "base/login.html", {"user_objs":user_objs})
二.自定义中间件
中间件可以定义五个方法,四个特点。 #五个方法: 1.process_request(self,request) 2.process_view(self, request, view_func, view_args, view_kwargs) 3.process_template_response(self,request,response) 4.process_exception(self, request, exception) 5.process_response(self, request, response) #四个特点: 1.执行时间。2.参数。3.执行顺序。4.返回值
只有process_request()方法返回HttpResponse对象时,会执行当前中间件的process_response()方法,process_view()和process_exception()方法有HttpResponse对象时,都会执行最后一个中间件的process_response()方法,然后倒序执行。
中间件其实就是request和response对象在各种process_..()方法之间的传值
1.process_request(self,request)
process_request只有一个参数request,request是http发来的请求的封装。它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给当前中间件的process_response函数,然后再通过其函数的return值返回给浏览器。
执行时间: 在执行视图函数之前,也在路由匹配之前 参数: request: 请求对象 和视图是同一个 执行的顺序: 按照中间件的注册顺序 顺序执行 返回值: None :正常流程,接着走process_view()、视图函数、process_response() HttpResponse:当前中间件之后的中间件的process_request、路由匹配、视图函数都不执行,直接执行当前中间的process_response的方法,并将HttpResponse对象传给process_response方法。然后倒序执行之前的process_response的方法,最终返回给浏览器
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): #没有返回值,或返回值为None print("MD1里面的 process_request") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2里面的 process_request") pass
2.process_response(self,request,response)
它有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。
执行时间: 在执行视图函数之后 参数: request: 请求对象 和视图是同一个 response: 返回的response对象 执行的顺序: 按照中间件的注册顺序 倒序执行 返回值: HttpResponse:必须返回response对象,用来接受视图函数返回的HttpResponse值
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1里面的 process_request") #不必须写return值 def process_response(self, request, response):#request和response两个参数必须有,名字随便取 print("MD1里面的 process_response") #print(response.__dict__['_container'][0].decode('utf-8')) #查看响应体里面的内容的方法,或者直接使用response.content也可以看到响应体里面的内容,由于response是个变量,直接点击看源码是看不到的,你打印type(response)发现是HttpResponse对象,查看这个对象的源码就知道有什么方法可以用了。 return response #必须有返回值,写return response ,这个response就像一个接力棒一样 #return HttpResponse('瞎搞') ,如果你写了这个,那么你视图返回过来的内容就被它给替代了 class MD2(MiddlewareMixin): def process_request(self, request): print("MD2里面的 process_request") pass def process_response(self, request, response): #request和response两个参数必须要有,名字随便取 print("MD2里面的 process_response") return response #必须返回response,不然你上层的中间件就没有拿到httpresponse对象,就会报错
3.process_view(self, request, view_func, view_args, view_kwargs)
它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用对应的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
执行时间: 在执行视图函数之前,在路由匹配之后 参数: request: 请求对象 和视图是同一个 view_func: 视图函数 view_args: 传递给视图函数的位置参数 分组的参数 view_kwargs: 传递给视图函数的关键字参数 命名分组的参数 执行的顺序: 按照中间件的注册顺序 顺序执行 返回值: None : 正常流程 HttpResponse:当前中间件之后的中间件的process_view、视图函数都不执行,直接执行最后一个中间的process_response的方法,然后倒序执行之前的process_response的方法,最终返回给浏览器
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1里面的 process_request") def process_response(self, request, response): print("MD1里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD1 中的process_view") print(view_func, view_func.__name__) #就是url映射到的那个视图函数,也就是说每个中间件的这个process_view已经提前拿到了要执行的那个视图函数 #ret = view_func(request) #提前执行视图函数,不用到了上图的试图函数的位置再执行,如果你视图函数有参数的话,可以这么写 view_func(request,view_args,view_kwargs) #return ret #直接就在MD1中间件这里这个类的process_response给返回了,就不会去找到视图函数里面的这个函数去执行了。 class MD2(MiddlewareMixin): def process_request(self, request): print("MD2里面的 process_request") pass def process_response(self, request, response): print("MD2里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD2 中的process_view") print(view_func, view_func.__name__)
4.process_exception(self, request, exception)
执行时间(触发条件): 在视图函数之后,视图层面有异常才执行 参数: request: 请求对象 和视图是同一个 exception: 错误对象 执行的顺序: 按照中间件的注册顺序 倒序执行 返回值: None : 交给下一个中间件处理异常,所有的中间件都没有处理,交给django处理 HttpResponse:当前中间件之前的中间件的process_exception不执行,直接执行最后一个中间的process_response的方法,然后倒序执行之前的process_response的方法,最终返回给浏览器
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1里面的 process_request") def process_response(self, request, response): print("MD1里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD1 中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("MD1 中的process_exception") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2里面的 process_request") pass def process_response(self, request, response): print("MD2里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD2 中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("MD2 中的process_exception")
views.py def login(req): if req.method == "GET": return render(req,"login.html") else: username = req.POST.get("username") password = req.POST.get("password") ret = models.User.objects.filter(username=username,password=password) if ret: req.session["status"] = True return redirect("/base/") else: return redirect("/login/") def base(req): return render(req,"base.html") middlewares.py #其实是给除了login函数之外的其他所有函数都写上装饰器 class MD1(MiddlewareMixin): def process_request(self, request): lst = ["/login/"] if request.path not in lst: if request.session.get("status") == True: pass else: return redirect("/login/") # print("MD1里面的 process_request")
三.Django生命周期
图解如下:
过程描述:
第一步:浏览器发起请求 第二步:WSGI创建socket服务端,将接受到的http请求封装成request对象。 第三步:将request请求发送给中间件处理 第四步:url路由,根据当前请求的URL找到视图函数 第五步:view视图,进行业务处理(ORM处理数据,从数据库取到数据返回给view视图;view视图将数据渲染到template模板;将数据返回) 第六步:中间件处理响应 第七步:WSGI返回响应(HttpResponse) 第八步:浏览器渲染