zoukankan      html  css  js  c++  java
  • Django学习笔记一十八——Django中间件的使用

    我们在前面学cookie的时候,学会了用装饰器来判定用户是否登录,如果已经登录了就可以访问页面,否则直接跳转到登录的页面。如果视图函数少的话这样是没什么问题的,可是如果有大量的视图,每个函数前都要加一个这种的装饰器,显然是不方便的,所以Django就为我们提供了一个个更加合适的方法来实现这种功能。

    什么是中间件?

     按照官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的HOOK,它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。

    但是由于作用域是全局,一定要谨慎使用,否则会影响性能。

    直白一点来说,中间件是帮我们在视图函数执行前和执行后做的一些额外的操作,因为它本质上就是一个自定义类,类里定义了几个方法,Django框架会在请求的特定时间中去执行这些方法。看看下面的图

     中间件的位置就决定了他的功能。

    中间件的使用

     我们看一下Django项目中的settings.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',
    ]

    其实我们做的想第一个项目,就对这个中间件进行了操作,把csrf那个类直接注释掉了。

    我们看一看这个中间件的源代码(导入以后在ctrl点击去)

    from django.middleware.csrf import CsrfViewMiddleware

     把另外几个也看一下,就会发现其实中间件其实的作用不外乎几种(除了下划线开头的内部方法)

    五种中间件的固定方法

    1. process_request
    2. process_view
    3. process_response
    4. process_exception
    5. process_template

    前面三种是我们常用的,着重要理解的是前两个。

    上面所有的方法返回值不过两种,一种是None,还有一种是HttpResponse。所以中间件的执行是有顺序的,设置文件中中间件的定义是一个列表,所以执行的顺序就是从上到下依次执行。如果第一个方法没有返回值,就按照列表的顺序往下走,否则就直接把HTTPResponse对象返回给用户。我们下面用一个最简单的自定义中间件来说明中间件的效果

    自定义中间件的使用

    定义一个最简单的视图函数,能返回个HttpResponse就可以,连模板都不用了

    def test(request):
        print('in views.test')
        return HttpResponse(11111)

    新建一个py文件,路径跟manage.py同级,然后声明两个类,py文件的文件名就叫my_middleware.py

    """
    文件名my_middleware.py
    自定义中间件
    """
    
    from django.utils.deprecation import MiddlewareMixin
    
    class MiddleWare_A(MiddlewareMixin):
        def process_request(self,request):
            print('这是中间件A')
    
    
    
    class MiddleWare_B(MiddlewareMixin):
        def process_request(self,request):
            print('这是中间件B')

    下面就是中间件的导入(这种用字符串导入包的方式点击这里查看)

    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',
        'my_middleware.MiddleWare_A',
        'my_middleware.MiddleWare_B'
    ]

    注意最后两行就是我们追加的自定义中间件,在访问页面的时候,就会打印出来下面的字符串

     因为我们先导入的是中间件A,所以就先执行A里的指令,反之也是成立的。在中间件执行完了以后才去执行视图里映射的函数。(因为是request请求处理,如果是response响应处理就是应该先执行视图里的函数。)

     而我们定义的函数是没有返回值的,所以返回值就默认为None,会继续执行下一个中间件。如果我们把MiddleWare_A修改一下,会有什么样的效果呢?

    class MiddleWare_A(MiddlewareMixin):
        def process_request(self,request):
            print('这是中间件A')
            return HttpResponse('中间件A返回值')

    再访问/test/,页面就显示了中间件的返回内容

     后台打印的数据也发生了变化

     就连视图里的函数都没有执行。

    请求处理和响应处理

     在上面一节我们用一个最简单的案例说明了中间件的原理和效,在5种中间件的使用中,最重要的就是请求处理和响应处理,我们这里看一下具体的使用注意事项

    请求处理

    请求处理:process_response(self,request)

    通过前面的演示已经很清楚了,有以下几点:

    • 执行顺序:按照注册的顺序(settings.py中从上到下的顺序)
    • 返回值:无返回值或返回值为None,继续只写那个后续中间件中的process_request方法
    •     返回response,不执行后面的中间件中的process_request和视图函数

    响应处理

    响应处理:process_response(self,request,response)

    把前面定义的A和B的中间件修改一下,增加一个响应处理,做一下测试

    class MiddleWare_A(MiddlewareMixin):
        def process_request(self,request):
            print('这是中间件A的请求处理')
    
        def process_response(self,request,response):
            print('中间件A里的响应处理')
            return response
    
    class MiddleWare_B(MiddlewareMixin):
        def process_request(self,request):
            print('这是中间件B的请求处理')
    
        def process_response(self,request,response):
            print('中间件B里的响应处理')
            return response

    注册的方式不变,先A后B,然后请求一下页面

    就会有下面的效果

     

     从运行的效果可以看出来,响应处理是在视图函数执行完毕以后才运行的,并且运行的顺序刚好和注册的顺序相反,是从列表最后向前面执行。

    并且和请求处理不同,响应处理必须有一个response类的返回值,整体的效果是这样的

    视图请求

     视图请求:process_view(self,request,view_func,view_args,view_kwargs)参数含义是这样的

    def process_view(self,request,view_func,view_args,view_kwargs):
        """
        :param request:浏览器发送的请求对象
        :param view_func:要执行的视图函数
        :param view_args:要执行的视图函数的位置参数
        :param view_kwargs:要执行的视图函数的关键字参数
    
        """
        pass

     和前面的process_response一样,我们把中间件A和B都添加一个process_view,运行一下看看效果

    class MiddleWare_A(MiddlewareMixin):
        def process_request(self,request):
            print('这是中间件A的请求处理')
    
        def process_response(self,request,response):
            print('中间件A里的响应处理')
            return response
    
        def process_view(self,request,view_func,view_args,view_kwargs):
            """
            :param request:浏览器发送的请求对象
            :param view_func:要执行的视图函数
            :param view_args:要执行的视图函数的位置参数
            :param view_kwargs:要执行的视图函数的关键字参数
    
            """
            print('中间件A里的process_view')
            print('A_view_func:——————',view_func,type(view_func))
    
    class MiddleWare_B(MiddlewareMixin):
        def process_request(self,request):
            print('这是中间件B的请求处理')
    
        def process_response(self,request,response):
            print('中间件B里的响应处理')
            return response
    
        def process_view(self,request,view_func,view_args,view_kwargs):
            print('中间件B中的process_view')
            print('B_view_func:——————',view_func)
    修改后的my_middleware.py

    访问一下,看看效果

     所以,process_view的执行顺序是按照注册的顺序从前到后,执行的时间是在路由找到映射的关系以后,但是在执行视图函数前。

    返回值是None时,会继续执行后续的中间件中的process_view方法。如果返回response对象就会跳过后面的process_view方法

    但是有一点要注意:process_view的返回值和process_response是没关系的,如果中间件存在process_response,最终的返回值是由process_response决定的。整个流程如下图所示

    也就是说不管process_request或process_view之间只要任何一个有返回的HttpResponse,视图函数都是不会执行的

    而浏览器最终的渲染内容是由最后的process_response决定的。

    异常处理和模板响应处理

     前面三种处理是最常见的后面还有两种处理方法不太常用,我们大概了解就行了。

    异常处理

    异常处理:process_exception(self,request,exception),当视图函数有异常抛出的时候才会执行

    执行顺序:按照注册时的倒叙执行

    执行时间:在视图函数抛出异常时执行

    返回值:None或HttpResponse,效果和process_request的返回值一样。

    模板响应处理

    模板响应处理process_template_response(self,request,response)用的就非常少了

    它的参数是一个HttpRequest对象,response是有视图或者中间件产生的TemplateResponse对象,也就是说它只能在视图函数执行完毕后才执行(视图必须返回一个render()方法,或者该对象是一个TemplateResponse对象或等价方法)

     这个使用的环境太少,就不讲了,如果需要用的时候再查查吧!

    中间件的使用案例

    结合两个案例来看一下中间件的使用

    url白名单

    白名单的实现比较简单。假设我们需要用一个白名单来限制被请求的url,通过中间件的功能实现,就把中间件写到前面的my_middleware.py文件中,新建一个列表,里面放上我们允许访问的url,如果请求访问的url不在列表内,就返回一个response,不执行后面的内容了。

    URLs = ['/test/']       #白名单列表
    
    
    #白名单处理
    class WhiteList(MiddlewareMixin):
        def process_request(self,request):
            url = request.path_info     #获取请求地址(不包含参数)
            if url in URLs:
                pass
            else:    
                return HttpResponse('无权访问该地址')

    这样就行了,是不是很简单,就不用在视图中对url进行判定了。在每次request的时候直接处理。

    登录状态判定

    在这一章一开始的时候就提到过,以前用装饰器的方式来判定登录状态需要对每个视图函数进行装饰,太麻烦了,所以就可以利用这个中间件的形式来操作。

    但是这里有个注意点:在注册的时候,因为我们的登录状态要用到session,所以一定要把自定义的中间件放在session的中间件的后面。

    中间件的定义也很简单,直接获取session的状态就可以

    class Login_Check(MiddlewareMixin):
    
        def process_request(self,request):
            log_stat = request.session.get('is_log')
            if log_stat == 1:
                pass
            return HttpResponse('请登录')

    实际的使用环境应该是如果没有登录状态时直接重定向到登录页面。并且在试的时候要加上一个添加session的过程,除非再添加一个session,总起来用法是这样的

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import redirect
    
    class Check(MiddlewareMixin):
        def process_request(self,request):
            if 'login' in request.path:
                return None
            log_stat = request.session.get('is_log')
            if log_stat == 1:
                return None
            return redirect('/session_test/login')
    my_middleware.py
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'my_middleware.Check',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    setting.py部分

    在中间件中,加上了对url的判断,就把login的页面排除掉了,否则就会一致重定向。

  • 相关阅读:
    RabbitMQ系列教程之七:RabbitMQ的 C# 客户端 API 的简介
    RabbitMQ系列教程之六:远程过程调用(RPC)
    git无法提交,存在未提交的修改,在重新合并前或者撤销更改
    安装mysql提示3306端口已经被占用解决方案
    区块链学习一基本知识
    超级账本 --- ReadWriteSet的逻辑结构
    解决windows10 里vs2015 附件进程调试提示“此任务要求应用程序有提升的权限”
    Fabric V1 交易的生命周期
    sql 取首次投资的人
    Win10年度更新开发必备:VS2015 Update 3正式版下载汇总
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/12875694.html
Copyright © 2011-2022 走看看