django七大中间件的作用,django的组件
在前面的课程中,我们已经学习了如何通过修饰view函数来判断用户是否登录,将未登录的用户跳转到登录页面。我们通过向几个特定的视图函数添加装饰器来实现这个需求。不过以后增加的视图功能可能还需要修饰,有点繁琐。
学完今天的内容,我们可以用更合适的方式实现对所有请求做同样操作的功能。
中间件简介什么是中间件?官方说法是,中间件是一个框架级的钩子,用于处理Django的请求和响应。它是一个轻量级的底层插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件负责完成一些特定的功能。
但因为它影响整个世界,所以需要小心使用,使用不当会影响性能。
说白了,中间件帮助我们在视图函数执行前后做一些额外的操作。它本质上是一个自定义类,其中定义了几个方法,Django framework会在请求的特定时间执行这些方法。
我们一直在使用中间件,只是没有注意到而已。打开Django项目的Settings.py文件,看到下图中的中间件配置项。
中间件=[
django . middleware . security . security middleware ,
django . contrib . sessions . middleware . session middleware ,
django . middleware . common . common middleware ,
django . middleware . csrf . csrfviewmiddleware ,
django . contrib . auth . middleware . authenticationmiddleware ,
django . contrib . messages . middleware . message middleware ,
django . middleware . click jacking . xframeoptions middleware ,
]
中间件配置项是一个列表,列表中有字符串。这些字符串其实就是类,也就是中间件。
我们之前已经接触过一个csrf相关的中间件?一开始我们让大家把他评论出来,然后他们提交帖子请求的时候也不会被拒绝。后来学会使用csrf_token后,他们就不再评论这个中间件了。
然后学习中间件中的方法,以及何时执行。
自定义中间件中间件可以定义五种方法,分别是:(主要是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对象。如果没有,它将根据django定义的规则继续向后执行。如果是HttpResponse对象,会直接返回给用户。
定制一个中间件示例。
从django.utils.deprecation导入MiddlewareMixin
MD1类(MiddlewareMixin):
def process_request(自身,请求):
打印(“MD1中的process_request”)
def process_response(自身、请求、响应):
打印(“MD1中的process_response”)
返回响应
Process_requestprocess_request有一个参数,就是request。该请求与查看功能中的请求相同。
它的返回值可以是None或HttpResponse对象。如果返回值为None,则按照正常流程进行,交给下一个中间件。如果是HttpResponse对象,Django不会执行view函数,而是将对应的对象返回给浏览器。
我们来看看Django是如何在多个中间件中执行process_request方法的。
从django.utils.deprecation导入MiddlewareMixin
MD1类(MiddlewareMixin):
def process_request(自身,请求):
打印(“MD1中的process_request”)
MD2类(MiddlewareMixin):
def process_request(自身,请求):
打印(“MD2中的process_request”)
及格
在settings.py的中间件配置项中注册以上两个自定义中间件:
中间件=[
django . middleware . security . security middleware ,
django . contrib . sessions . middleware . session middleware ,
django . middleware . common . common middleware ,
django . middleware . csrf . csrfviewmiddleware ,
django . contrib . auth . middleware . authenticationmiddleware ,
django . contrib . messages . middleware . message middleware ,
django . middleware . click jacking . xframeoptions middleware ,
中间件。 MD1 ,#自定义中间件MD1
中间件。MD2 #定制中间件MD2
]
此时,当我们访问一个视图时,我们会发现终端中打印了以下内容:
MD1中的流程请求
MD2中的流程请求
在app01的索引视图中,改变MD1和MD2的位置,然后访问一个视图,你会发现终端中打印的内容如下:
MD2中的流程请求
MD1中的流程请求
根据app01中index视图的结果,我们知道view函数是最后执行的,MD2在MD1之前执行了自己的process_request方法。
打印两个自定义中间件的process_request方法中的request参数,你会发现它们是同一个对象。
总而言之:
中间件的process_request方法在view函数执行之前执行。配置多个中间件时,会按照中间件中的注册顺序,也就是列表的索引值,从前到后执行。不同中间件之间传递的请求都是同一个对象。
多个中间件中的process_response方法按照在中间件中的注册顺序以相反的顺序执行,即首先执行第一个中间件的process_request方法,最后执行其process_response方法,最后执行最后一个中间件的process_request方法,首先执行其process_response方法。
Process_response它有两个参数,一个是请求,一个是响应。request是上例中的同一个对象,response是view函数返回的HttpResponse对象。此方法的返回值也必须是HttpResponse对象。
将process_response方法添加到上面的M1和M2中:
从django.utils.deprecation导入MiddlewareMixin
MD1类(MiddlewareMixin):
def process_request(自身,请求):
打印(“MD1中的process_request”)
def process_response(自身、请求、响应):
打印(“MD1中的process_response”)
返回响应
MD2类(MiddlewareMixin):
def process_request(自身,请求):
打印(“MD2中的process_request”)
及格
def process_response(自身、请求、响应):
打印(“MD2中的process_response”)
返回响应
访问一个视图并查看终端的输出:
MD2中的流程请求
MD1中的流程请求
app01中的索引视图
MD1中的流程响应
从结果中可以看到MD2中的process_response:
process_response方法在view函数之后执行,顺序是MD1在MD2之前执行。(此时在settings.py中MD2先于MD1注册)
多个中间件中的process_response方法按照在中间件中的注册顺序以相反的顺序执行,即首先执行第一个中间件的process_request方法,最后执行其process_response方法,最后执行最后一个中间件的process_request方法,首先执行其process_response方法。
process_viewprocess_view(自身,请求,视图功能,视图参数,视图参数)
该方法有四个参数。
是HttpRequest对象。
View_func是Django即将使用的视图函数。(是实际的函数对象,不是字符串形式的函数名。)
View_args是将传递给视图的位置参数列表。
View_kwargs是将被传递给视图的关键字参数的字典。view_args和view_kwargs都不包含第一个视图参数(请求)。
Django会在调用视图函数之前调用process_view方法。
它应该返回None或一个HttpResponse对象。如果没有返回,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后执行相应的视图。如果它返回一个HttpResponse对象,Django将不会调用适当的视图函数。它将执行中间件的process_response方法,并将其应用于HttpResponse,然后返回结果。
将process_view方法添加到MD1和MD2:
从django.utils.deprecation导入MiddlewareMixin
MD1类(MiddlewareMixin):
def process_request(自身,请求):
打印(“MD1中的process_request”)
定义流程_响应(自身、请求、响应):
打印( MD1里面的流程_响应)
返回响应
def process_view(self,request,view_func,view_args,view_kwargs):
打印(- * 80)
打印( MD1中的流程视图)
print(view_func,view_func .__name__)
MD2类(MiddlewareMixin):
定义流程请求(自身,请求):
打印( MD2里面的process _ request’)
及格
定义流程_响应(自身、请求、响应):
打印( MD2里面的流程_响应)
返回响应
def process_view(self,request,view_func,view_args,view_kwargs):
打印(- * 80)
打印( MD2中的流程视图)
print(view_func,view_func .__name__)
访问指数视图函数,看一下输出结果:
MD2里面的流程_请求
MD1里面的流程_请求
-
MD2中的流程_视图
0x000001DE68317488索引处的函数索引
-
MD1中的流程_视图
0x000001DE68317488索引处的函数索引
app01中的指数视图
MD1里面的流程_响应
MD2里面的流程_响应
流程_视图方法是在流程_请求之后,视图函数之前执行的,执行顺序按照中间件中的注册顺序从前到后顺序执行的
进程异常进程异常(自身,请求,异常)
该方法两个参数:
一个对象对象
一个例外是视图函数异常产生的例外对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个没有人也可以是一个HttpResponse对象。如果是HttpResponse对象姜戈将调用模板和中间件中的流程_响应方法,并返回给浏览器,否则将默认处理异常。如果返回一个没有,则交给下一个中间件的流程_异常方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
给MD1和MD2添加上这个方法:
从django.utils.deprecation导入MiddlewareMixin
MD1类(MiddlewareMixin):
定义流程请求(自身,请求):
打印( MD1里面的process _ request’)
定义流程_响应(自身、请求、响应):
打印( MD1里面的流程_响应)
返回响应
def process_view(self,request,view_func,view_args,view_kwargs):
打印(- * 80)
打印( MD1中的流程视图)
print(view_func,view_func .__name__)
定义进程_异常(自身、请求、异常):
打印(例外)
打印( MD1中的process _ exception’)
MD2类(MiddlewareMixin):
定义流程请求(自身,请求):
打印( MD2里面的process _ request’)
及格
定义流程_响应(自身、请求、响应):
打印( MD2里面的流程_响应)
返回响应
def process_view(self,request,view_func,view_args,view_kwargs):
打印(- * 80)
打印( MD2中的流程视图)
print(view_func,view_func .__name__)
定义进程_异常(自身、请求、异常):
打印(例外)
打印( MD2中的process _ exception’)
如果视图函数中无异常,流程_异常方法不执行。
想办法,在视图函数中抛出一个异常:
定义索引(请求):
打印(应用01中的指数视图)
提高值错误(呵呵)
返回HttpResponse(O98K )在MD1的流程_异常中返回一个响应对象:
MD1类(MiddlewareMixin):
定义流程请求(自身,请求):
打印( MD1里面的process _ request’)
定义流程_响应(自身、请求、响应):
打印( MD1里面的流程_响应)
返回响应
def process_view(self,request,view_func,view_args,view_kwargs):
打印(- * 80)
打印( MD1中的流程视图)
print(view_func,view_func .__name__)
定义进程_异常(自身、请求、异常):
打印(例外)
打印( MD1中的process _ exception’)
返回HttpResponse(str(exception)) #返回一个响应对象
看输出结果:
MD2里面的流程_请求
MD1里面的流程_请求
-
MD2中的流程_视图
0x0000022C09727488索引处的函数索引
-
MD1中的流程_视图
0x0000022C09727488索引处的函数索引
app01中的指数视图
呵呵
MD1中的流程_异常
MD1里面的流程_响应
MD2里面的流程_响应
注意,这里并没有执行MD2的流程_异常方法,因为MD1中的流程_异常方法直接返回了一个响应对象。
流程_模板_响应(用的比较少)流程_模板_响应(自身、请求、响应)
它的参数,一个对象对象,响应是模板响应对象(由视图函数或者中间件产生)。
流程_模板_响应是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个渲染()方法(或者表明该对象是一个模板响应对象或等价方法)。
MD1类(MiddlewareMixin):
定义流程请求(自身,请求):
打印( MD1里面的process _ request’)
定义流程_响应(自身、请求、响应):
打印( MD1里面的流程_响应)
返回响应
def process_view(self,request,view_func,view_args,view_kwargs):
打印(- * 80)
打印( MD1中的流程视图)
print(view_func,view_func .__name__)
定义进程_异常(自身、请求、异常):
打印(例外)
打印( MD1中的process _ exception’)
返回HttpResponse(str(exception))
定义流程_模板_响应(自身、请求、响应):
打印( MD1中的流程_模板_响应)
返回响应
MD2类(MiddlewareMixin):
定义流程请求(自身,请求):
打印( MD2里面的process _ request’)
及格
定义流程_响应(自身、请求、响应):
打印( MD2里面的流程_响应)
返回响应
def process_view(self,request,view_func,view_args,view_kwargs):
打印(- * 80)
打印( MD2中的流程视图)
print(view_func,view_func .__name__)
定义进程_异常(自身、请求、异常):
打印(例外)
打印( MD2中的process _ exception’)
定义流程_模板_响应(自身、请求、响应):
打印( MD2中的流程_模板_响应)
返回响应
views.py中:
定义索引(请求):
打印(应用01中的指数视图)
定义渲染():
打印("在索引/呈现中")
返回HttpResponse(O98K )
rep=HttpResponse(OK )
再现渲染=渲染
退货代表
访问指数视图,终端输出的结果:
MD2里面的流程_请求
MD1里面的流程_请求
-
MD2中的流程_视图
0x000001C111B97488索引处的函数索引
-
MD1中的流程_视图
0x000001C111B97488索引处的函数索引
app01中的指数视图
MD1中的流程_模板_响应
MD2中的流程_模板_响应
在索引/渲染中
MD1里面的流程_响应
MD2里面的流程_响应
从结果看出:
视图函数执行完之后,立即执行了中间件的流程_模板_响应方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的提出方法,返回了一个新的HttpResponse对象,接着执行中间件的流程_响应方法。
中间件的执行流程上一部分,我们了解了中间件中的5个方法,它们的参数、返回值以及什么时候执行,现在总结一下中间件的执行流程。
请求到达中间件之后,先按照正序执行每个注册中间件的流程请求方法,流程_请求方法返回的值是没有,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的流程_请求方法,而是执行当前对应中间件的流程_响应方法,将HttpResponse对象返回给浏览器。也就是说:如果中间件中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的流程_请求和流程_响应方法都不执行,顺序执行3,2,1中间件的流程_响应方法。
流程_请求方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的流程_视图方法,流程_视图方法返回没有,继续按顺序执行,所有流程_视图方法执行完后执行视图函数。加入中间件3的流程_视图方法返回了HttpResponse对象,则4,5,6的流程_视图以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的流程_响应方法开始倒序执行。
流程_模板_响应和流程_异常两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:
中间件版登录验证中间件版的登录验证需要依靠会话,所以数据库中要有姜戈_session表。
urls.py
从django.conf.urls导入全球资源定位器(Uniform Resource Locator)
从app01导入视图
urlpatterns=[
url(r^index/$,观点指数),
url(r^login/$,views.login,name=login’),
]urls.py
views.py
快捷方式导入渲染,HttpResponse,重定向
定义索引(请求):
返回HttpResponse(“这是索引")
定义主页(请求):
返回HttpResponse(“这是家")
定义登录(请求):
if request.method==POST :
用户=请求. POST.get(用户)
pwd=请求POST.get(pwd )
如果user==Q1mi 和pwd==123456 :
# 设置会议
request.session[用户]=用户
# 获取跳到登陆页面之前的统一资源定位器
next_url=请求. GET.get(下一个)
# 如果有,就跳转回登陆之前的统一资源定位器
if next_url:
返回重定向(下一个网址)
# 否则默认跳转到指数页面
否则:
返回重定向(/index/)
返回render(request,“log in . html”)views . py
login.html
!声明文档类型
html lang=en
头
meta charset=UTF-8
meta http-equiv= x-ua-compatible content= IE=edge
meta name= viewport content= width=device-width,initial-scale=1
标题登录页面/标题
/头
身体
表单操作={% url 登录名 %}
p
=用户的标签用户名:/标签
输入类型=text name=user id=user
/p
p
=pwd 的标签密码:/标签
输入类型=文本名称=pwd id=pwd
/p
输入类型=提交值=登录
/表单
/body
/html login.html
中间件。巴拉圭
类AuthMD(MiddlewareMixin):
white_list=[/login/,] #白名单
balck_list=[/black/,] #黑名单
定义流程请求(自身,请求):
快捷方式导入重定向,HttpResponse
next_url=request.path_info
print(请求路径信息,请求获取完整路径()
if next_url in self.white_list或request.session.get(user ):
返回
self.balck_list中的elif next_url:
返回HttpResponse(“这是一个非法的网址”)
否则:
返回重定向(/login/?next={} .格式(下一个网址))登录校验中间件
在settings.py中注册
中间件=[
姜戈。中间件。安全。安全中间件,
姜戈。贡献。会话。中间件。会话中间件,
姜戈。中间件。常见。通用中间件,
姜戈。中间件。csrf。 csrfviewmiddleware ,
姜戈。贡献。auth。中间件。认证中间件,
姜戈。贡献。消息。中间件。消息中间件,
中间件 AuthMD ,
]settings.py中注册中间件
AuthMD中间件注册后,所有的请求都要走AuthMD的流程_请求方法。
访问的统一资源定位器在白名单内或者会议中有用户用户名,则不做阻拦走正常流程;
如果统一资源定位器在黑名单中,则返回这是一个非法网址的字符串;
正常的统一资源定位器但是需要登录后访问,让浏览器跳转到登录页面。
注:AuthMD中间件中需要会话,所以AuthMD注册的位置要在会议中间的下方。
附:Django请求流程图
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。