Django's middleware and form other usage

Middleware five commonly used methods:

  • process_request(self,request)

    • process_request has one parameter, the request, and the request as a function of the view. Its return value can be None can be HttpResponse object. The return value is None, continue to follow the normal process, the middleware to the next process, if it is HttpResponse object, Django view function will not be performed, and the corresponding object is returned to the browser.

    • Example:

      应用下自定义一个文件夹,自定义一个py文件:
      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配置:
      在MIDDLEWARE列表中加入
      'app01.mymiddleware.my.MD1',
      'app01.mymiddleware.my.MD2',
      
      执行结果是:
      MD1的process_request
      MD2的process_request
  • process_response(self,request,reponse)

    • process_response method multiple middleware is registered in accordance with MIDDLEWARE in reverse order of 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. Further, he has two parameters, a request, is a response, response is returned by the function HttpResponse object view. The return value of the method must be HttpResponse object.

    • process_response method is performed after the view function.

    • Example:

      from django.utils.deprecation import MiddlewareMixin
      
      
      class MD1(MiddlewareMixin):
      
          def process_request(self, request):
              print("MD1里面的 process_request")
              #不必须写return值
          def process_response(self, request, response):#request和response两个参数必须有,名字随便取
              print("MD1里面的 process_response")
              #print(response.__dict__['_container'][0].decode('utf-8')) #查看响应体里面的内容的方法,或者直接使用response.content也可以看到响应体里面的内容,由于response是个变量,直接点击看源码是看不到的,你打印type(response)发现是HttpResponse对象,查看这个对象的源码就知道有什么方法可以用了。
           return response  #必须有返回值,写return response  ,这个response就像一个接力棒一样
              #return HttpResponse('瞎搞') ,如果你写了这个,那么你视图返回过来的内容就被它给替代了
      
      class MD2(MiddlewareMixin):
          def process_request(self, request):
              print("MD2里面的 process_request")
              pass
      
          def process_response(self, request, response): #request和response两个参数必须要有,名字随便取
              print("MD2里面的 process_response") 
              return response  #必须返回response,不然你上层的中间件就没有拿到httpresponse对象,就会报错
      
      
      settings配置与上方示例一致
      
      打印的结果是:
      MD1里面的process_request
      MD2里面的process_request
      MD2里面的process_response
      MD1里面的process_response
  • process_view(self,request,view_func,view_args,view_kwargs)

    • The method takes four parameters:

      • request is subject HTTPRequest

      • view_func is Django view function that will be used. (Which is actually a function of the object, rather than as a function of the name string.)

      • view_args list is passed to the position of the view parameters

      • View_kwargs dictionary key parameter is passed to the view, view_args view_kwargs not included with a view of a first function (request).

      • Django calls the view process_view method before calling the function.

      • It should return None or an HttpResponse object. If it returns None, Django will continue to process the request, the middleware process_view perform any other method, and then perform a corresponding view. If it returns an HttpResponse object, django view function does not call the object. It process_response method performed middleware and application and return the results to the HttpResponse.

      • flow chart:

      • Example:

        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__) #就是url映射到的那个视图函数,也就是说每个中间件的这个process_view已经提前拿到了要执行的那个视图函数
                #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")
                pass
        
            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__)
        
        
        settings配置如上:
        执行结果是:
        MD1里面的 process_request
        MD2里面的 process_request
        MD1 中的process_view
        <function index at 0x000001DE68317488> index
        MD2 中的process_view
        <function index at 0x000001DE68317488> index
        MD2里面的 process_response
        MD1里面的 process_response
      • After process_request process_view method, before reprocess_response, executed before the view function is executed in the order MIDDLEWARE registration order from front to back order of execution, as

  • process_exception(self,request,exception)

    • This method takes two parameters:

      • An HttpRequest object

      • Exception exception is a view of an object produced by an abnormal function.

      • This method only exception occurs and we have to perform in view of the function, the value it returns can be a None, it can also be a HttpResponse object. If HttpResponse object, Django will call the templates and process_response method middleware, and returned to the browser, otherwise it will default to handle exceptions. If a return None, the next to the middleware process_exception method to handle the exception. It's execution order is executed in reverse order of registration of middleware.

      • flow chart:

      • Example:

        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")
                pass
        
            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))
        
        views.py代码:#抛出异常,不然process_exception方法不执行
        def index(request):
            print("app01 中的 index视图")
            raise ValueError("呵呵")
            return HttpResponse("O98K")
        settings配置如上:
        执行结果:
        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
      • Note that the above example does not perform process_exception method of MD1, MD2 as process_exception method directly returns a response object, FIG.

  • process_template_response(self,request,response)

    • The method is relatively small, its parameter, a HttpRequest object, response is TemplateResponse object (generated by the view function or middleware).

    • 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")
              pass
      
          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视图")
        #raise ValueError('出错啦') 
          def render():
              print("in index/render")  
              #raise ValueError('出错啦') #至于render函数中报错了,那么会先执行process_template_response方法,然后执行process_exception方法,如果是在render方法外面报错了,那么就不会执行这个process_template_response方法了。
              return HttpResponse("O98K") #返回的将是这个新的对象
          rep = HttpResponse("OK")
          rep.render = render
          return rep
      
      settings配置如上:
      执行结果是:
      MD1里面的 process_request
      MD2里面的 process_request
      --------------------------------------------------------------------------------
      MD1 中的process_view
      <function index at 0x000001EA6771BBF8> index
      --------------------------------------------------------------------------------
      MD2 中的process_view
      <function index at 0x000001EA6771BBF8> index
      MD2 中的process_template_response
      MD1 中的process_template_response
      MD2里面的 process_response
      MD1里面的 process_response
    • 从结果不难看出:视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD2的,在执行MD1的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的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方法开始倒序执行。

    • 如图:
  • process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

    • 如图:

中间件版登陆认证:

  • 中间件版的登录验证需要依靠session,所以数据库中要有django_session表。

  • 配置urls.py

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url(r'^index/$', views.index),
        url(r'^login/$', views.login, name='login'),
    ]
  • 配置views.py

    from django.shortcuts import render, HttpResponse, redirect
    
    
    def index(request):
        return HttpResponse('this is index')
    
    
    def home(request):
        return HttpResponse('this is home')
    
    
    def login(request):
        if request.method == "POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    
            if user == "Q1mi" and pwd == "123456":
                # 设置session
                request.session["user"] = user
                # 获取跳到登陆页面之前的URL
                next_url = request.GET.get("next")
                # 如果有,就跳转回登陆之前的URL
                if next_url:
                    return redirect(next_url)
                # 否则默认跳转到index页面
                else:
                    return redirect("/index/")
        return render(request, "login.html")
  • login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>登录页面</title>
    </head>
    <body>
    <form action="{% url 'login' %}">
        <p>
            <label for="user">用户名:</label>
            <input type="text" name="user" id="user">
        </p>
        <p>
            <label for="pwd">密 码:</label>
            <input type="text" name="pwd" id="pwd">
        </p>
        <input type="submit" value="登录">
    </form>
    </body>
    </html>
  • middlewares.py

    class AuthMD(MiddlewareMixin):
        white_list = ['/login/', ]  # 白名单
        balck_list = ['/black/', ]  # 黑名单
    
        def process_request(self, request):
            from django.shortcuts import redirect, HttpResponse
    
            next_url = request.path_info
            print(request.path_info, request.get_full_path())
    
            if next_url in self.white_list or request.session.get("user"):
                return
            elif next_url in self.balck_list:
                return HttpResponse('This is an illegal URL')
            else:
                return redirect("/login/?next={}".format(next_url))
  • 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',
        'middlewares.AuthMD',
    ]
  • AuthMD中间件注册后,所有的请求都要走AuthMD的process_request方法。

  • 访问的URL在白名单内或者session中有user用户名,则不做阻拦走正常流程;

  • 如果URL在黑名单中,则返回This is an illegal URL的字符串;

  • 正常的URL但是需要登录后访问,让浏览器跳转到登录页面。

  • 注:AuthMD中间件中需要session,所以AuthMD注册的位置要在session中间的下方。

  • Django请求流程图

Ajax通过csrf的第三种方式:即jQuery设置cookie

<script src="{% static 'jquery.js' %}"></script>
<script src="{% static 'jquery.cookie.js' %}"></script>
<script>
    $('#btn').click(function () {
        var uname = $('[type="text"]').val();
        var pwd = $('[type="password"]').val();
        $.cookie('xx','sss');
        $.ajax({
            url:'/login/',
            type:'post',
            headers:{'X-CSRFToken':$.cookie('csrftoken')}, //设置请求头
            data:{uname:uname,pwd:pwd,},
            success:function (res) {
                console.log(res);
            }
        })
    })
</script>

csrf详解:

详述CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。攻击者通过HTTP请求将数据传送到服务器,从而盗取回话的cookie。盗取回话cookie之后,攻击者不仅可以获取用户的信息,还可以修改该cookie关联的账户信息。

  所以解决csrf攻击的最直接的办法就是生成一个随机的csrftoken值,保存在用户的页面上,每次请求都带着这个值过来完成校验。

form组件

  • 作用:

    1. 生成页面可用的HTML标签
    2. 对用户提交的数据进行校验
    3. 保留上次输入内容
  • 使用步骤:

    • 第一步:创建form类

      from django.shortcuts import render,HttpResponse
      from django import forms
      class LoginForm(forms.Form):
          username = forms.CharField(
              label="用户名",
              required=True, #不能为空
              max_length=7, #长度不能超过7个字符
              min_length=2, #最短不能低于2个字符
              initial="小骚浩", #初始值
              widget=forms.TextInput(attrs={'class':'c1',"placeholder":"请输入用户名"}),
              error_messages={
                  'required':"用户名不能为空",
                  'min_length':"太短了"
              }
          )
          password = forms.CharField(
              required=True,
              label="密码",
              widget=forms.PasswordInput(attrs={'class':'c1',"placeholder":"请输入密码"}),
          )
          sex = forms.ChoiceField(
              choices=[(1,'男'),(2,"女")],
              widget=forms.RadioSelect(attrs={'xx':'None'}),
          )
          hobby = forms.MultipleChoiceField(
              choices=[(1,'逛街'),(2,'打游戏'),(3,'烫头')],
              widget=forms.CheckboxSelectMultiple,
          )
          bothday = forms.CharField(
              widget=forms.TextInput(attrs={'type':'date'})
          )
    • 第二步:在views中实例化这个类对象,并交给前端html页面

      def login(request):
          if request.method == "GET":
              forms_obj = LoginForm()
              return render(request,"login.html",{'forms_obj':forms_obj})
          else:
              forms_obj = LoginForm(request.POST)
              status = forms_obj.is_valid() #开始校验
              return render(request,'login.html',{'forms_obj':forms_obj})
    • 第三步:进行数据格式校验

              forms_obj = LoginForm(request.POST)
              status = forms_obj.is_valid() #开始校验
    • 第四步:login.html页面

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>登录页面</title>
          <style>
              .c1{
                  background-color: orangered;
              }
              ul{
                  list-style: none;
              }
          </style>
      </head>
      <body>
      <form action="" method="post" novalidate>
          {% csrf_token %}
          <div>
              <label for="{{ forms_obj.username.id_for_label }}">{{ forms_obj.username.label }}</label>
              {{ forms_obj.username }}
              <span>{{ forms_obj.username.errors.0 }}</span>
          </div>
              <div>
              <label for="{{ forms_obj.password.id_for_label }}">{{ forms_obj.password.label }}</label>
                  {{ forms_obj.password }}
                  <span>{{ forms_obj.username.errors.0 }}</span>
          </div>
          <div>
              <label for="{{ forms_obj.sex.id_for_label }}">{{ forms_obj.sex.label }}</label>
              {{ forms_obj.sex }}
          </div>
          <div>
              <label for="{{ forms_obj.hobby.id_for_label }}">{{ forms_obj.hobby.label }}</label>
              {{ forms_obj.hobby }}
          </div>
          <div>
              <label for="{{ forms_obj.bothday.id_for_label }}">{{ forms_obj.bothday.label }}</label>
              {{ forms_obj.bothday }}
          </div>
      </form>
      </body>
      </html>

Guess you like

Origin www.cnblogs.com/ghh520/p/11973822.html