zoukankan      html  css  js  c++  java
  • Django组件-中间件

    Django组件-中间件

     

    1、中间件的概念

      中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

      Django的中间件的定义:

    `Middleware ``is` `a framework of hooks into Django’s request``/``response processing. <br>It’s a light, low``-``level “plugin” system ``for` `globally altering Django’s ``input` `or` `output.`

      如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

      可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

      Django默认的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',
    ]

      MIDDLEWARE配置项是一个列表,列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。

      我们之前已经接触过一个csrf相关的中间件了?我们一开始让大家把他注释掉,再提交post请求的时候,就不会被forbidden了,后来学会使用csrf_token之后就不再注释这个中间件了。

      那接下来就为大家解开神秘的面纱,深入探索一下。学习中间件中的方法以及这些方法什么时候被执行。

    2、自定制中间件

      中间件可以定义五个方法,分别是:

      • process_request(self,request)

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

      • process_exception(self, request, exception)

      • process_response(self, request, response)

      • process_template_response(self,request,response)(了解)

    3、自定制中间件示例

    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

    4、process_request方法

      process_request有一个参数,就是request,这个request和视图函数中的request是一样的。

      它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将响应对象返回给浏览器。

      我们来看看多个中间件时,Django是如何执行其中的process_request方法的。

    from django.utils.deprecation import MiddlewareMixin


    class MD1(MiddlewareMixin):

      def process_request(self, request):
          print("MD1里面的 process_request")


    class MD2(MiddlewareMixin):
      def process_request(self, request):
          print("MD2里面的 process_request")

      在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',
      'middlewares.MD1', # 自定义中间件MD1
      'middlewares.MD2' # 自定义中间件MD2
    ]

      此时,我们访问一个视图,会发现终端中打印如下内容:

    `MD1里面的 process_request``MD2里面的 process_request``app01 中的 index视图`

      把MD1和MD2的位置调换一下,再访问一个视图,会发现终端中打印的内容如下:

    `MD2里面的 process_request``MD1里面的 process_request``app01 中的 index视图`

      看结果我们知道:视图函数还是最后执行的,MD2比MD1先执行自己的process_request方法。

      在打印一下两个自定义中间件中process_request方法中的request参数,会发现它们是同一个对象。

      由此总结一下:

    1. 中间件的process_request方法是在执行视图函数之前执行的。

      1. 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。

        1. 不同中间件之间传递的request都是同一个对象

    5、process_response方法

      它有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。

      给上述的M1和M2加上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


    class MD2(MiddlewareMixin):
      def process_request(self, request):
          print("MD2里面的 process_request")

      def process_response(self, request, response):
          print("MD2里面的 process_response")
          return response

      访问一个视图,看一下终端的输出:

    `MD1里面的 process_request``MD2里面的 process_request``app01 中的 index视图``MD2里面的 process_response``MD1里面的 process_response`
    

      看结果可知:

        process_response方法是在视图函数之后执行的,并且顺序是MD1比MD2先执行。(此时settings.py中 MD2比MD1先注册)

        多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

    6、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并返回结果。

      给MD1和MD2添加process_view方法:

    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__)
    
    
    class MD2(MiddlewareMixin):
        def process_request(self, request):
            print("MD2里面的 process_request")
    
        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__)
    

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

    `MD1里面的 process_request``MD2里面的 process_request``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``MD1 中的process_view``<function index at ``0x000001DE68317488``> index``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``MD2 中的process_view``<function index at ``0x000001DE68317488``> index``app01 中的 index视图``MD2里面的 process_response``MD1里面的 process_response`
    

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

    7、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("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")
    
        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")
    

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

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

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

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

    class MD2(MiddlewareMixin):
    
        def process_request(self, request):
            print("MD2里面的 process_request")
    
        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")
            return HttpResponse(str(exception))  # 返回一个响应对象
    

      看输出结果:

    MD1里面的 process_request
    MD2里面的 process_request
    --------------------------------------------------------------------------------
    MD1 中的process_view
    <function index at 0x0000022C09727488> index
    --------------------------------------------------------------------------------
    MD2 中的process_view
    <function index at 0x0000022C09727488> index
    app01 中的 index视图
    呵呵
    MD2 中的process_exception
    MD2里面的 process_response
    MD1里面的 process_response
    

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

    8、process_template_response(了解)

      process_template_response(self, request, response)

      该方法参数:

      • HttpRequest对象

      • response是TemplateResponse对象(由视图函数或者中间件产生)。

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

    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")
            return HttpResponse(str(exception))
    
        def process_template_response(self, request, response):
            print("MD1 中的process_template_response")
            return response
    
    
    class MD2(MiddlewareMixin):
        def process_request(self, request):
            print("MD2里面的 process_request")
    
        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")
    
        def process_template_response(self, request, response):
            print("MD2 中的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视图,终端输出的结果:

    `MD1里面的 process_request``MD2里面的 process_request``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``MD1 中的process_view``<function index at ``0x000000000B46DBF8``> index``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``-``MD2 中的process_view``<function index at ``0x000000000B46DBF8``> index``app01 中的 index视图``MD2 中的process_template_response``MD1 中的process_template_response``in` `index``/``render``MD2里面的 process_response``MD1里面的 process_response`
    

      从结果看出:

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

    9、源码试读

      作为延伸扩展内容,有余力的同学可以尝试着读一下以下两个自带的中间件:

    `'django.contrib.sessions.middleware.SessionMiddleware'``,``'django.contrib.auth.middleware.AuthenticationMiddleware'``,`
    
  • 相关阅读:
    ZOJ Problem Set–2417 Lowest Bit
    ZOJ Problem Set–1402 Magnificent Meatballs
    ZOJ Problem Set–1292 Integer Inquiry
    ZOJ Problem Set–1109 Language of FatMouse
    ZOJ Problem Set–1295 Reverse Text
    ZOJ Problem Set–1712 Skew Binary
    ZOJ Problem Set–1151 Word Reversal
    ZOJ Problem Set–1494 Climbing Worm
    ZOJ Problem Set–1251 Box of Bricks
    ZOJ Problem Set–1205 Martian Addition
  • 原文地址:https://www.cnblogs.com/zengxiaowen/p/11838661.html
Copyright © 2011-2022 走看看