zoukankan      html  css  js  c++  java
  • django 第七章 中间件



    前言

    Django 中间件是修改 Django request 或者 response 对象的钩子,可以理解为是介于 HttpRequest 与 HttpResponse 处理之间的一道处理过程。每个中间件组件负责做一些特定的功能。例如,Django 包含一个中间件组件 AuthenticationMiddleware,它使用会话将用户与请求关联起来。

    浏览器从请求到响应的过程中,Django 需要通过很多中间件来处理,可以看如下图所示:

    Django 中间件作用:

    • 修改请求,即传送到 view 中的 HttpRequest 对象。
    • 修改响应,即 view 返回的 HttpResponse 对象。

    中间件组件配置在 settings.py 文件的 MIDDLEWARE 选项列表中。配置中的每个字符串选项都是一个类,也就是一个中间件。


    Django 默认的中间件配置:

    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',
    ]
    



    自定义中间的步骤

    1. 在 app01 目录下新建一个 middle.py 文件,名字可自定义,并在该 py 文件中导入 MiddlewareMixin

    自定义中间件,必须继承父类 MiddlewareMixin

    from django.utils.deprecation import MiddlewareMixin
    
    class Middles(MiddlewareMixin):  # 继承父类
        def process_request(self, request):
            print('process_request')
        def process_response(self, request, response):
            print('process_response')
            return response
    

    参数说明:

    process_request(self,request)

    request 和视图函数中的 request 是一样的。

    方法的返回值可以是 None 也可以是 HttpResponse 对象。返回值是 None 的话,按正常流程继续走,交给下一个中间件处理。返回值是 HttpResponse 对象,Django 将不执行后续视图函数之前执行的方法以及视图函数,直接以该中间件为起点,倒序执行中间件,且执行的是视图函数之后执行的方法。

    process_response(self, request, response)

    request 是请求对象,response 是视图函数返回的 HttpResponse 对象,该方法必须要有返回值,且必须是response。

    response 方法是在视图函数之后执行的。当配置多个中间件时,会按照 MIDDLEWARE 中的注册顺序,也就是列表的索引值,倒序执行。


    1. 在 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',
        'app01.middle.Middles',      # 自定义中间件   
    ]
    

    1. 启动Django服务器执行页面后结果:


    中间件执行流程图:

    从下图看,正常的情况下按照绿色的路线进行执行;假设中间件1有返回值,则按照红色的路线走,直接执行该类下的 process_response 方法返回,后面的其他中间件就不会执行。


    • process_view

    process_view(request, view_func, view_args, view_kwargs)

    request 是一个 HttpRequest 对象。
    view_func 是一个 Django 将要使用的 Python 函数。(这是一个真实的函数对象,不是函数的名称)
    view_args 是一个用来传递给视图的位置参数列表;
    view_kwargs 是一个用来传递给视图的关键字参数字典。
    view_args 和 view_kwargs 都不包含第一个视图参数 ( request )。

    from django.utils.deprecation import MiddlewareMixin
    
    class Middles(MiddlewareMixin):  # 继承父类
        def process_request(self, request):
            print('process_request')
        def process_response(self, request, response):
            print('process_response')
            return response
        def process_view(self,request, view_func, view_args, view_kwargs):
            print("process_view 方法!")    #在视图之前执行 顺序执行
            #return view_func(request, *view_args, **view_kwargs)
    

    只在 Django 调用视图前被调用。

    它应该返回 None 或 HttpResponse 对象。

    • 如果它返回 None ,Django 将继续处理这个请求,执行任何其他的 process_view() ,然后执行相应的视图。

    • 如果它返回 HttpResponse 对象,Django 不会去影响调用相应的视图;它会将响应中间件应用到 HttpResponse 并返回结果。


    中间件执行流程:
    从下图看,正常的情况下按照绿色的路线进行执行;假设中间件1的 view 方法 有返回值,则按照红色的路线走,跳过中间件2的 view 方法和视图函数,直接开始执行 process_response 方法流程返回。


    • process_exception

    process_exception(self, request, exception)

    • request 是一个 HttpRequest 对象。
    • exception 是一个由视图函数引发的 Exception 对象。

    方法只有当视图引发异常时,Django 会调用 process_exception()。在视图函数之后,在 process_response 方法之前执行。

    process_exception() 应该返回 None 或 HttpResponse 对象。
    返回值是 None,页面会报 500 状态码错误,视图函数不会执行。process_exception 方法倒序执行,然后再倒序执行 process_response 方法。
    返回值是 HttpResponse 对象,页面不会报错,返回状态码为 200。
    视图函数不执行,该中间件后续的 process_exception 方法也不执行,直接从最后一个中间件的 process_response 方法倒序开始执行。若是 process_view 方法返回视图函数,提前执行了视图函数,且视图函数报错,则无论 process_exception 方法的返回值是什么,页面都会报错, 且视图函数和 process_exception 方法都不执行。


    • rocess_template_response

    默认情况不执行:

    from  django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class M1(MiddlewareMixin):
        def process_request(self, request):
            print('M1.request')
        def process_view(self, request,callback,callback_args,callback_kwargs ):
            print("M1.process_view")
        def process_response(self, request, response):
            print('M1.response')
            return response
        def process_exception(self, request,exception):
            print('M1的process_exception')
    
    class M2(MiddlewareMixin):
        def process_request(self, request):
            print('M2.request')
        def process_view(self, request,callback,callback_args,callback_kwargs ):
            print("M2.process_view")
        def process_response(self, request, response):
            print('M2.response')
            return response
        def process_exception(self, request, exception):
            print('M2的process_exception')
        def process_template_response(self,request,response):
            print('M2process_template_response')
            return response
    

    执行结果:



    只有在视图函数的返回对象中有render方法才会执行!
    并把对象的render方法的返回值返回给用户(注意不返回视图函数的return的结果了,而是返回视图函数 return值(对象)的render方法)

    # 视图函数
    from django.shortcuts import render,HttpResponse
    class Foo():
        def __init__(self,requ):
            self.req=requ
        def render(self):
            return HttpResponse('OKKKK')
    
    def index(request):
        print("执行index")
        obj=Foo(request)
        return obj
    
    from  django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class M1(MiddlewareMixin):
        def process_request(self, request):
            print('M1.request')
        def process_view(self, request,callback,callback_args,callback_kwargs ):
            print("M1.process_view")
        def process_response(self, request, response):
            print('M1.response')
            return response
        def process_exception(self, request,exception):
            print('M1的process_exception')
    
    class M2(MiddlewareMixin):
        def process_request(self, request):
            print('M2.request')
        def process_view(self, request,callback,callback_args,callback_kwargs ):
            print("M2.process_view")
        def process_response(self, request, response):
            print('M2.response')
            return response
        def process_exception(self, request, exception):
            print('M2的process_exception')
        def process_template_response(self,request,response):
            #如果视图函数中的返回值 中有render方法,才会执行 process_template_response
            print('M2process_template_response')
            return response
    

    执行结果:


    既然process_template_respnse,不返回视图函数的return的结果,而是返回视图函数 return值(对象)的render方法;(多加了一个环节)就可以在这个视图函数返回对象的 render方法里,做返回值的二次加工了!多加工几个,视图函数就可以随便使用了!

    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    class Dict():   #对视图函数返回值做二次封装 !!
        def __init__(self,requ,msg):
            self.req=requ   
            self.msg=msg
        def render(self):
            a=self.msg 
            #在render方法里面 把视图函数的 返回值 制作成字典 、列表等。。。 
            #如果新增了其他 一个视图函数直接,return对象 即可!不用每个视图函数都写 制作字典 列表 拼接的逻辑了
            return HttpResponse(a)
    
    def index(request):
        print("执行index")
        obj=Dict(request,"vv")
        return obj
    



    中间件应用场景

    由于中间件工作在 视图函数执行前、执行后(像不像所有视图函数的装饰器!)适合所有的请求/一部分请求做批量处理。

    1、做IP限制:
      放在 中间件类的列表中,阻止某些IP访问了;

    2、URL访问过滤:
      如果用户访问的是login视图(放过)
      如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在 多个视图函数上写装饰器了!

    3、缓存(还记得CDN吗?):
      客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数




  • 相关阅读:
    ES6 Promise 用法转载
    移动端滚动性能优化
    Python之禅
    Day01~15
    Python
    第一章 Java起源
    IMP-00009: 导出文件异常结束 imp
    浏览器访问网页的详细内部过程
    数据库连接池
    连接数据库 六大步骤
  • 原文地址:https://www.cnblogs.com/hoyun/p/15686784.html
Copyright © 2011-2022 走看看