Django: Middleware

1.MIDDLEWARE Middleware

  • Between an intermediate process between the request and response process, the middleware is a lightweight, low-level plug-in system, and for changing the output data of django globally, the practical effect is to try to perform a function before and after do some additional operations.

  • Middleware is defined:

    如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
      说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

2 custom middleware

  • Middleware can define five methods:
    • 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)
这五种方法常用的process_request,process_view,process_response
这五种方法返回值返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则继续执行,如果是HttpResponse对象,则直接将该对象返回用户
  • Requesting a user will pass through all intermediate piece, this time requesting porcess_request, and finally to large views of the function, the function processing views, once again passes through the intermediate piece, in this case process_response, and finally returned to the requestor.

1. simple custom middleware

  • Create a package in the project, the name utils (arbitrary name from), then create a py file. Here test middlewares.py

    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
    #自定义中间件,不是必须要有下面这两个方法,有request方法说明请求来了要处理,有response方法说明响应出去时需要处理,不是非要写这两个方法,如果你没写process_response方法,那么会一层一层的往上找,哪个中间件有process_response方法就将返回对象给哪个中间件
  • Registered in the self-defined intermediate in MIDDLEWARE CI settgings.py

    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',
        'utils.middlewares.MD1',
    ]

2.process_request

  • process_request

    • carried out:

      Execution order execution time
      Executed in the order of registration Prior view function
    • Parameters: request

    • Return value: According to the order of registration

      return value effect
      None Normal flow continues to go to the next processing middleware
      HttpResponse Django view function will not be performed, the corresponding object is returned to the browser
  • Example:

    #middlewares.py  自定义中间件函数
    from django.utils.deprecation import MiddlewareMixin
    class MD1(MiddlewareMixin):
        def process_request(self,request):#执行MD1  process_request 就会打印
            print("MD1 process_request")
    
    class MD2(MiddlewareMixin):
        def process_request(self,request):#执行MD2  process_request 就会打印
            print("MD2 process_request")
    
    #views.py   视图函数
    def index(request):
        print("index 视图函数")
        return render(request,"index.html")
    #settings.py  注册侧MD1,MD2自定义中间件
    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',
        'utils.middlewares.MD1',
        'utils.middlewares.MD2',
    ]
    #结果:
    #MD1 process_request
    #MD2 process_request
    #index 视图函数
    #如果MD1和MD2位置交换则结果:
    #MD2 process_request
    #MD1 process_request
    #index 视图函数
    • It can be summarized:
      • Middleware process_request method is performed before view function
      • When a plurality of intermediate, will be registered in accordance MIDDLEWARE order list performed sequentially from front to back
      • The request is transmitted between different middleware same object can be verified by ID (request)

3.process_response

  • process_response

    • carried out:

      Execution order execution time
      Registered in the order of execution flashback After the view function
    • Parameters: request, response

    • return value:

      return value effect
      return response HttpResponse object view response is returned by the function
  • Process_response multiple middleware method in accordance with the registration order MIDDLEWARE reverse execution, that is the first middleware process_request method is performed first, and its final implementation process_response method, the last method middleware last process_request execution, its process_response method is executed first.

  • Examples

    • Note :
      • When defining process_response, you must request and response must have two parameters.
      • When defining process_response, you must have a return value, write return response, otherwise you will not get the upper middleware httpresponse objects, the error will be: AttributeError: 'NoneType' Object attribute has NO 'GET'
      • Use response.content body inside can be seen that the response content. Since the response is variable, simply click to see the source code is not visible.
    from django.utils.deprecation import MiddlewareMixin
    class MD1(MiddlewareMixin):
        def process_request(self,request):
            print("MD1 process_request")
            # print(id(request))
        def process_response(self,request,response):
            print(response.content)
            print("MD1 process_response")
    
    
    class MD2(MiddlewareMixin):
        def process_request(self,request):
            print("MD2 process_request")
            # print(id(request))
        def process_response(self,request,response):
            print("MD1 process_response")
    
    #MD1 process_request
    #MD2 process_request
    #index 视图函数
    #MD2 process_response
    #MD1 process_response
    • When we MD1 process_request method of setting a return HttpResponse ( "hello")
    
    from django.shortcuts import HttpResponse
    from django.utils.deprecation import MiddlewareMixin
    class MD1(MiddlewareMixin):
        def process_request(self,request):
            print("MD1 process_request")
            # print(id(request))
            return HttpResponse("hello")
        def process_response(self,request,response):
            print("MD1 process_response")
            print(response.content)
            return response
    # MD1 process_request
    #MD1 process_response
    #b'hello'   响应体输出的内容response.content
    
    #process_request方法里面不写返回值,默认也是返回None,如果你自己写了return None,也是一样的效果,不会中断你的请求,但是如果你return 的一个httpresponse对象,那么就会在这个方法中断你的请求,直接返回给用户,这就成了非正常的流程了。并且,如果你在这里return了httpresponse对象,那么会从你这个中间件类中的process_response方法开始执行返回操作,所以这个类里面只要有process_response方法,肯定会执行
    • flow chart:

  • Exercise: Set the path whitelist, as long as access is login landing path, do not do this cookie authentication

    from django.urls import reverse
    class MD3(MiddlewareMixin):
        def process_request(self,request):
            if request.path not in [reverse('login')]:
                print("中间件MD3")
                is_login = request.COOKies.get("is_login",False)
                if is_login:
                    pass
                else:
                    return redirect(reverse("login"))
            else:
                return None
    
        def process_response(self,request,response):
            print("MD3响应")
            return response

4.process_view

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

    • carried out:

      Execution order execution time
      Executed in the order of registration Prior view function, process_request after
    • parameter:

      parameter Explanation
      request HttpRequest object is
      view_func Django is a view function that will be used (which is the actual function object, not the name of the function as a string)
      view_args The list is passed to the position of the view parameters
      view_kwargs It is passed to the keyword arguments dictionary views
    • return value:

      return value effect
      None Django will continue processing this request
      return response Django view corresponding function is not called, process_response it performs a method and middleware application and return the results to the HttpResponse
    • flow chart

  • Add to MD1 and MD2 process_view method:

    from django.shortcuts import HttpResponse,redirect,render
    from django.utils.deprecation import MiddlewareMixin
    class MD1(MiddlewareMixin):
        def process_request(self,request):
            print("MD1 process_request")
            # print(id(request))
        def process_response(self,request,response):
            print("MD1 process_response")
            # print("响应体",response.content)
            return response
        def process_view(self,request,view_func,view_args,view_):
            print("*"*32)
            print("MD1  process_view")
            print(view_func, view_func.__name__)
          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")
            # print(id(request))
        def process_response(self,request,response):
            print("MD2 process_response")
            return response
        def process_view(self,request,view_func,view_args,view_):
            print("*"*32)
            print("MD2  process_view")
            print(view_func, view_func.__name__)#url映射到的那个视图函数,也就是说每个中间件的这个process_view已经提前拿到了要执行的那个视图函数
    
    
    #MD1 process_request
    #MD2 process_request
    #********************************
    #MD1  process_view
    #<function index at 0x0000022D0146E378> index
    #********************************
    #MD2  process_view
    #<function index at 0x0000022D0146E378> index
    #index 视图函数
    #MD2 process_response
    #MD1 process_response
    • process_view method after process_reuqest, before process_response, before view function, the execution order in registration order MIDDLEWARE front to back order execution.

5.process_exception

  • process_exception(self,request,exception)

    • carried out:

      Execution order execution time
      Performed in reverse order of registration View layer was wrong execution (required trigger)
    • parameter:

    parameter Explanation
    request The request object
    exception Exception object view function abnormality generated
    • return value
    return value effect
    None Next to a middleware process_exception method to handle the exception. It's execution order is executed in reverse order of registration of middleware.
    return response Is HttpResponse object, Django will call the templates and process_response method middleware, and returned to the browser, otherwise it will default to handle exceptions
  • flow chart:

  • Add process_exception in MD1, MD2 in

    from django.shortcuts import HttpResponse,redirect,render
    from django.utils.deprecation import MiddlewareMixin
    class MD1(MiddlewareMixin):
        def process_request(self,request):
            print("MD1 process_request")
            # print(id(request))
        def process_response(self,request,response):
            print("MD1 process_response")
            # print("响应体",response.content)
            return response
        def process_view(self,request,view_func,view_args,view_):
            print("*"*32)
            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")
            # print(id(request))
        def process_response(self,request,response):
            print("MD2 process_response")
            return response
        def process_view(self,request,view_func,view_args,view_):
            print("*"*32)
            print("MD2  process_view")
            print(view_func, view_func.__name__)
    
        def process_exception(self, request, exception):
            print(exception)
            print("MD2 中的process_exception")
    • Because the view is no exception, so process_exception method does he trigger exceptions
    def index(request):
        print("index 视图函数")
        raise ValueError("自己触发异常")
        return render(request,"index.html")
    • It returns a response object in the MD1 in process_exeception
    class MD1(MiddlewareMixin):
        def process_request(self,request):
            print("MD1 process_request")
            # print(id(request))
        def process_response(self,request,response):
            print("MD1 process_response")
            # print("响应体",response.content)
            return response
        def process_view(self,request,view_func,view_args,view_):
            print("*"*32)
            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))#返回一个字符串
    # MD1 process_request
    # MD2 process_request
    # ********************************
    # MD1  process_view
    # <function index at 0x000001E9C0C9E378> index
    # ********************************
    # MD2  process_view
    # <function index at 0x000001E9C0C9E378> index
    # index 视图函数
    # MD2 中的process_exception
    # 自己触发异常
    # MD1 中的process_exception
    # MD2 process_response
    # MD1 process_response
    • Code Flowchart:

6.process_template_response

  • process_template_response(self, request, response)

    • 执行:

      执行顺序 执行时间
      按照注册的顺序 倒叙执行 视图返回的是一个templateResponse对象(触发)
    • 参数:

      参数 解释
      request 一个HttpRequest对象
      return response TemplateResponse对象(由视图函数或者中间件产生)
    • 返回值:

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

      from django.shortcuts import HttpResponse,redirect,render
      from django.utils.deprecation import MiddlewareMixin
      class MD1(MiddlewareMixin):
          def process_request(self,request):
              print("MD1 process_request")
              # print(id(request))
          def process_response(self,request,response):
              print("MD1 process_response")
              # print("响应体",response.content)
              return response
          def process_view(self,request,view_func,view_args,view_):
              print("*"*32)
              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")
              # print(id(request))
          def process_response(self,request,response):
              print("MD2 process_response")
              return response
          def process_view(self,request,view_func,view_args,view_):
              print("*"*32)
              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):
              response.template_name = "login.html"#更改页面
              response.context_data["name"] = "haha"#更改传入值
              print("MD2 中process_template_response")
              return response

      views.py

      from django.template.response import TemplateResponse
      def index(request):
          print("index 视图函数")
          return TemplateResponse(request,"index.html",{"name":"xjk"})
      • 视图函数执行完毕后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD2的,再执行MD1的。MD2的process_template_response方法,返回一个新的HttpResponse对象,接着执行中间件的process_response方法

3.中间件的执行流程

  • 请求到达中间件之后,先按照正序执行每个注册中间件的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两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

Guess you like

Origin www.cnblogs.com/xujunkai/p/11848540.html