zoukankan      html  css  js  c++  java
  • django学习第十三天--自定义中间件

    jquery操作cookie

    • 下载地址
          http://plugins.jquery.com/cookie/
    
    • 引入
          <script type="text/javascript" src="js/jquery.min.js"></script>
          <script type="text/javascript" src="js/jquery.cookie.js"></script>
    
    • cookie操作
          设置值:
          $.cookie('the_cookie','the_value');
          #设置7天有效期
          $.cookie('the_cookie','the_value',{expires:7});
          
          读取
          $.cookie('the_cookie'); #通过键来取值
    
          删除cookie
          $.cookie('the_cookie',null); #通过传递null作为cookie的值即可
    

    中间件

    配置文件

          项目主目录中的配置文件是django留给开发者使用的用户级别配置文件
          实际上django有一个自己的默认全局配置文件
          那么他们的关系如下
    
          #django默认配置
          from django.conf import global_settings
    
          #用户级别配置
          from django_middleware import settinigs
    
          from django.conf import settings  #中间人
          #比如需要引入配置中的某个配置项settings.APPEND_SLASH,那么这样的引入的查找顺序是这样的,先去用户级别settings.py文件中找这个配置,如果没有找到,那么再去global_settings中去找默认配置
    

    django请求生命周期

          中间件用来对请求和响应做一些统一加工和处理的,比如对所有请求中的post请求做一个csrftoken认证,就用到了我们的'django.middleware.csrf.CsrfViewMiddleware',后面视图中能够使用request.session做一个session相关操作,这个request.session的功能就是在这个中间件中加工好的'django.contrib.sessions.middleware.SessionMiddleware'
    

    自定义中间件

    • 登录认证、权限认证、频率访问限制、请求数据统计等等...
    • 自定义中间的步骤
          1.应用文件夹下面创建一个文件夹,名字随便起,比如叫作mymiddleware
          2.在mymiddleware文件夹下面创建一个py文件,名称随意,比如叫做middlewares.py
          3.在middlewares.py文件中写上如下内容
    
          from django.utils.deprecation import MiddlewareMixin
          class LoginAuth(MiddlewareMixin):
                def process_request(self,request):
                      print('xxx')
    
          4.settings.py配置文件中写上如下内容
          MIDDLEWARE = [
                ....
                '应用名.中间文件夹.中间文件.类'
                'app01.mymiddleware.middlewares.LoginAuth', #配置中间件类,告诉django,我写的这个自定义中间件,你帮我使用上,一般都是放到最后,不然上面几个中间件的相关功能就没办法使用上了。
                #如果中间件功能不想用了,就注释掉它就行了。
                #以上几步搞定后,所有请求都会触发我们的中间件类中的process_request方法。
                ]
    
    • 登录认证中间示例
          中间件代码如下
          #登录认证中间件
          class LoginAuth(MiddlewareMixin):
                #/login/登录请求,应该正常放行,让他能获得login.html页面
                #添加一个白名单,这样首页登录就不需要登录认证
                white_list = ['/login/',]
                def process_request(self,request):
                      print('请求来啦!!!')
                      #获取当前请求路径:request.path /login/
                      #如果当前请求路径在白名单里面,我们不进行登录认证
                      if not request.path in self.white_list:
                            is_login = request.session.get('is_login') #True
                            if not is_login:
                                  return redirect('/login/')
    
    
          #视图代码
          def login(request):
                if request.method == 'GET':
                      return render(request,'login.html')
                else:
                      #print('xxxxxx')
                      uname = request.POST.get('username')
                      if uname == 'root':
                            request.session['is_login'] = True
                            return redirect('/home/')#告诉浏览器向/home/发送get请求获取页面
                      else:
                            return redirect('/login/')
    
          def home(request):
                print('home')
                return render(request,'home.html')
    
          def index(request):
                print('index')
                return render(request,'index.html')
    
          #执行步骤:如判断用户访问home页面,是否已经登录过了
          第一次请求的时候,先是走的中间件process_request,login路径,在白名单里面,所以就不会走下面的判断,
          实际后面会有个return None,就表示是正常返回,可以省略不用写,然后再去执行视图逻辑,获取到login页面,get请求获取login页面。
          第二次填写数据发送post请求,又会走一遍process_request,正常返回后再去执行视图逻辑,后台获取发送来的数据,
          设置session,然后重定向到home页面,重定向的时候又会走了一遍process_request,然后中间件会判断这个重定向的路径,最后再执行视图逻辑。
          下次想直接访问home页面的时候,先是发送/home/请求,先走中间件process_request,判断当前的路径是不是在白名单里,
          显然不在,然后执行下面的逻辑代码,获取到session中的键值对,如获取到了,return None,那么就会执行视图里面的逻辑,就直接执行home函数。
          如没有获取到,那么直接在中间件代码里面直接就重定向到login页面。
          
    

    中间件的五个方法

    整个中间件的执行顺序

          process_request从上到下,process_response从下到上
    
    • 五个方法: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) #响应
    

    每个方法的执行流程

    • 1.process_request
          class Md1(MiddlewareMixin):
                def process_request(self,request):
                      print('MD1--process_request')
                      #当process_request返回时None,可以默认不写,那么才会继续执行后面的中间件的process_request,如果你是最后一个中间件,并且你返回的是None,那么逻辑会继续执行到我们的url路由控制器
                      #但是当process_request里面return的是一个HttpResponse对象,那么后面的中间件的process_request将不再执行,也不会走到url路由控制器
                      #return HttpResponse('中间件md1的逻辑,没有通过!!!')
    
          class Md2(MiddlewareMixin):
                def process_request(self,request):
                      print('MD1--process_request')
    
    
          views.py代码
          def home(request):
              print('home')
              return render(request,'home.html')
          执行流程--中间件正常return None的情况:
                MD1--process_request
                MD2--process_request
                home
          
          执行流程--中间件Md1中响应回复对象的情况:
                MD1--process_request
          因为Md1中return的是响应对象,所以就不会再向下执行了,同时也不会去执行逻辑代码。
                     
    
    • 2.process_response
          class Md1(MiddlewareMixin):
                def process_request(self,request):
                      print('MD1--process_request')
                
                def process_response(self,request,response):
                      :param request:   当前请求对象
                      :param response:   视图函数的响应对象
                      :return:
                      print('Md1--响应')
                      #可以对响应内容做统一处理,如加响应头
                      response['xx'] = 'oo'
                      print(response.content) #获取响应回复内容 #b'ok'
                      #注意,如果你写了process_response方法,那么这个方法必须return response
                      return response
    
          class Md2(MiddlewareMixin):
                def process_request(self,request,response):
                      print('MD2--process_request')
          
                def process_response(self,request,response):
                      print('MD2--响应')
                      # if response.content != b'ok':
                            #如果process_response方法里面return了一个HttpResponse对象,那么这个对象会覆盖视图返回来的HttpResponse对象
                            #return HttpResponse('响应不OK!!!')
                      return response
          
          views.py文件
          def home(request):
                print('home')
                return render(request,'home.html')
                #return HttpResponse('我是home响应')
    
          执行流程  正常执行:
          MD1--process_request  #中间件请求从上至下
          MD2--process_request
          home                  #请求结束会后执行视图逻辑
          MD2--process_response #中间响应从下至上
          MD1--process_response
    
          执行流程 中间件HttpResponse响应覆盖视图返回来的Httpresponse对象:
          MD1--process_request  #中间件请求从上至下
          MD2--process_request
          home                  #执行视图逻辑,响应我是home响应
          MD2--process_response #中间件响应从下至上,覆盖视图响应对象响应不OK!!!
          MD1--process_response
    
    
    • 注意事项
          当中间件1的process_request方法return的是一个HttpResponse,那么会执行中间件1的process_response方法,不会去执行中间件2的方法了
    

    • 3.process_view(self,request,view_func,view_args,view_kwargs)
          from django.shortcuts import render,redirect,HttpResponse
          from django.utils.deprecation import MiddlewareMix
          
          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('MD1--process_view')
    
          class Md2(MiddlewareMixin):
                def process_request(self,request):
                      print('MD2--process_request')
    
                def process_response(self,request,response):
                      :param request:
                      :param view_func:   此次请求要执行的视图函数对象
                      :param view_args:  要函数的参数
                      :param view_kwargs: 要函数的参数
                      :return:
                      print('MD2--process_response')
                      return response
    
                def process_view(self,request,view_func,view_args,view_kwargs):
                      print('MD2--process_view')
    
    
                执行流程:
                MD1--process_request  #中间件请求从上至下
                MD2--process_request
                MD1--process_view   #中间件视图从上至下
                MD2--process_view
                中间件2执行函数名称 home  
                home                 #逻辑视图
                MD2--process_response  #中间件响应 从下至上
                MD1--process_response
    
    • process_view图解

    • 4.process_exception(self,request,exception)

          当视图函数出现错误或者异常时,自动触发的方法,能够捕获视图出现的错误,进行一些错误的统一处理
    
          from django.shortcuts import render,redirect,HttpResponse
          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('MD1--process_view')
    
                def process_exception(self,request,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('MD2--process_view')
                      
                def process_exception(self,request,exception):
                      from django.core.exceptions import PermissionDenied
                      # print('>>>>>>', exception, type(exception))
                      # if isinstance(exception,PermissionDenied):
                            #     return HttpResponse('权限不够!!!!!')
                            #>>>>>> 权限不够 <class 'django.core.exceptions.PermissionDenied'>
                            # >>>>>> 出错啦!!!
                      print('MD2--process_exception')
    
          views.py代码
          from django.core.exceptions import PermissionDenied #为了演示错误
          def home(request):
                print('home')
                raise PermissionDenied('权限不够')
                return render(request,'home.html')
    
          执行流程:
          MD1--process_request #中间件请求从上至下
          MD2--process_request
          MD1--process_view   #中间件视图从上至下
          MD2--process_view
          home                #逻辑视图
          MD2--process_exception  #中间件错误从下至上
          MD1--process_exception
          MD2--process_response  #中间件响应从下至上
          MD1--process_response
    
    • process_exception图解

    • 5.process_template_response(self,request,reponse)

          from django.shortcuts import render,redirect,HttpResponse
          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('MD1--process_view')
    
                def process_exception(self,request,exception):
                      print('MD1--process_view')
    
                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_requeust')
    
                def process_response(self,request,response):
                      print('MD2--process_response')
    
                def process_view(self,request,view_func,view_args,view_kwargs):
                      print('MD2--process_view')
    
                def process_exception(self,request,exception):
                      print('MD2--process_exception')
    
                def process_template_response(self,request,response):
                      print('MD2--process_template_response')
                      return response
    
          views.py代码
          def home(request):
                print('home')
                def render():
                      print('你好render')
                      return HttpResponse('你好response')
                ret = HttpResponse('ojbk')
                #必须给HttpResponse对象封装一个render属性等于一个render函数,才能触发中间件里面的process_template_response方法
                ret.render = render
                return ret
    
    
          执行流程:
          MD1--process_request  #中间件请求从上至下
          MD2--process_request
          MD1--process_view      #中间件视图从上至下
          MD2--process_view
          home                  #视图逻辑
          MD2--process_template_response   #中间件模板 从下至上
          MD1--process_template_response
          你好render                  #视图逻辑里面的render()函数中响应对象
          MD2--process_response      #中间件响应 从下至上
          MD1--process_response
    

    总结下中间件执行流程

      请求到达中间件之后,先按照正序执行每个注册中间件的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方法开始倒序执行。
    

    url路由系统补充---include路由分发和命名空间 namespace

    • 1.创建app
          python manage.py startapp app01
    
    • 2.配置app,在settings.py文件中
          INSTALLED_APPS = [
                      ...
                      'app02',
                ]
    

    路由分发步骤

    • 1.在项目主目录下的urls.py(以后我们称之为总路由)文件中,写上如下内容
          from django.conf.urls import url,inclue
          from django.contrib import admin
          #路由分发功能
          urlpatterns = [
                url(r'^admin/',admin.site.urls),
                url(r'^app01/',include('app01.urls')),#include参数格式'应用名称.urls'
                url(r'^app02/',include('appo2.urls')),
                #/app01/index/  先在总路由中匹配前面的路径,然后匹配到了,拿剩下的index/,去app01应用下面的urls.py文件进行路径匹配
          ]
    
    • 2.在每个应用文件夹下面创建一个ursl.py文件,里面内容
          from django.conf.urls import url,include
          from app01 import views
          urlpatterns = [
                url(r'^index/',views.index),
          ]
    

    问题,当两个应用中的url的别名相同了,使用反向解析的时候该怎么解决

          app01的urls.py
          from django.conf.urls import url,include
          from app01 import views
          urlpatterns = [
                url(r'^index/',views.index),
                url(r'^home/',views.home,name='home'),
          ]
    
          app02下的urls.py
          from django.conf.urls import url,include
          from app02 import views
          urlpatterns = [
                url(r'^index/',views.index),
                url(r'^home/',views.home,name='home'),
          ]
    
          app01的views.py文件进行别名解析
          def index(request):
                print('app01>>>',reverse('home'))
                return HttpResponse('app01-index')
    
          app02的views.py文件进行别名解析
          def index(request):
                print('app02>>>',reverse('home'))
                return HttpResponse('app02-index')
    
          以上执行完后,发现别名冲突,导致反向解析出错了
    

    解决办法,用命名空间

          总路由写法
          from django.conf.urls import url,include
          from django.contrib import admin
          #路由分发
          urlpatterns = [
                url(r'^app01/',include('app01.urls',namespace='app01')),
                url(r'^app02/',include('app02.urls',namespace='app02')),
          ]
    
          app01视图写法
          def index(request):
                print('app01>>>',reverse('app01:home'))
                return HttpResponse('app01-index')
    
          app02视图写法
          def index(request):
                print('app02>>',reverse('app02:home'))
                return HttpResponse('app02-index')
    
          模板中使用
          {% url 'app01:home' %}
    

    路由分发如何设置首页

          如果我们想通过输入http://127.0.0.1:8000/app01/,看到app01这个应用的首页,怎么办?就像现在输入一个http://127.0.0.1:8000来查看网站的首页,怎么办?
    
          url(r'^$', views.index),#以空开头,还要以空结尾,写在项目的urls.py文件里面就是项目的首页,写在应用文件夹里面的urls.py文件中,那就是app01的首页
    
    

    整个完整请求-中间件-后台逻辑处理的过程

    -------------------------------------------

    个性签名:代码过万,键盘敲烂!!!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

  • 相关阅读:
    1201JavaScript事件(Events)
    1201Js对象##正则表达式##
    CSS样式表基本概念
    1124Js基础语法
    网页学习大纲(1116/1130适用于预习或复习)
    1117网页基础--表单
    1117网页基础--框架frameset / iframe
    数据库基础(触发器)
    数据库基础(视图)
    数据库基础(定义变量来查询的练习、存储过程)
  • 原文地址:https://www.cnblogs.com/weiweivip666/p/13394615.html
Copyright © 2011-2022 走看看