Django之中间件与form其他用法

中间件常用的五种方法:

  • process_request(self,request)

    • process_request有一个参数,就是request,与视图函数中的request一样。它的返回值可以是None也可以是HttpResponse对象。返回值是None,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。
    • 示例:
      应用下自定义一个文件夹,自定义一个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方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。另外,他有两个参数,一个是request,一个是response,response是视图函数返回的HttpResponse对象。该方法的返回值必须是HttpResponse对象。
    • process_response方法是在视图函数之后执行的。
    • 示例:
      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)
    • 该方法有四个参数:

      • request是HTTPRequest对象
      • view_func是Django即将使用的视图函数。(它是实际的函数对象,而不是函数的名称作为字符串。)
      • view_args是将传递给视图的位置参数的列表
      • view_kwargs是将传递给视图的关键字参数的字典,view_args与view_kwargs都不包含第一个视图函数(request).
      • Django会在调用视图函数之前调用process_view方法。
      • 它应该返回None或者一个HttpResponse对象。如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。如果它返回一个HttpResponse对象,django不会调用对象的视图函数。它将执行中间件的process_response方法并将应用到该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("-" * 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
      • process_view方法是在process_request之后,reprocess_response之前,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的,如图
  • process_exception(self,request,exception)
    • 该方法两个参数:

      • 一个HttpRequest对象
      • 一个exception是视图函数异常产生的Exception对象。
      • 这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None,也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
      • 流程图:
      • 示例:
        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
      • 注意,上述示例并没有执行MD1的process_exception方法,因为MD2中的process_exception方法直接返回一个响应对象,如图
  • process_template_response(self,request,response)
    • 该方法用的比较少,它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。
    • 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>

原文地址:https://www.cnblogs.com/ghh520/p/11973822.html

时间: 2024-07-30 22:21:31

Django之中间件与form其他用法的相关文章

Django中间件 及 form 实现用户登陆

Django中间件 及 form 实现用户登陆 Form 验证 密码调用md5 加密存储 form.add_error("字段名", "错误信息") 自定义错误信息 装饰器实现 用户认证 中间件实现 用户认证 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影响到性能. django默认的中间件在settings.py中 当用户发起请求

Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块

目录 使用Django对中间件的调用思想完成自己的功能 功能要求 importlib模块介绍 功能的实现 csrf中间件详细介绍 跨站请求伪造 Django csrf中间件 form表单 ajax csrf相关装饰器 在CBV上加csrf装饰器 Django settings源码剖析及模仿使用 Django settings源码剖析 查看内部配置文件 模仿使用 Auth模块 auth简介 auth模块常用方法 创建用户 校验用户名和密码 保存用户登录状态 判断当前用户是否登录 校验原密码 修改密

Django【十三】form组件。

一.form组件 form组件的功能: 检验功能 前端生成HTML页面 还能保留输入的内容 form组件的用法: from django import forms # Create your views here. # 定义一个类 class Myform(forms.Form): title = forms.CharField( # 通过from表单进行验证的时候,验证输入title字段的数据,参数用于验证 max_length=20, min_length=2, ) # CharField/

12.Django基础十之Form和ModelForm组件

一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确.如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.. Django form组件就实现了上面所述的功能. 总结一下,其实form组件的主要功能如下: 生成页面可用的HTML标签 对用户提交的数据进行校验 保留上次输入内容 普通方式手写注册功能

Django基础十之Form和ModelForm组件

一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确.如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.. Django form组件就实现了上面所述的功能. 总结一下,其实form组件的主要功能如下: 生成页面可用的HTML标签 对用户提交的数据进行校验 保留上次输入内容 普通方式手写注册功能

django 自定义中间件 middleware

Django 中间件 Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出.中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性,其它的MVC框架也有这个功能,名称为IoC. Django在中间件中预置了五个方法,这五个方法的区别在于不同的阶段执行,对输入或输出进行干预,方法如下: 1)初始化:无需任何参数,服务器响应第一个请求的时候调用一次,用于确定是否启用当前中间件. def __init__(

Django组件:中间件

一.中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影响到性能. Django的中间件的定义: Middleware is a framework of hooks into Django’s request/response processing. <br>It’s a light, low-level “plugin” system for gl

ajax和form表单,django的中间件

1.前后端传输编码格式contentType: urlencoded: 对应的数据格式:name=XXX&password=66 后端获取数据:request.POST django会将urlencoded编码的数据解析自动放到request.POST formdata: form表单传输文件的编码格式 后端获取文件格式数据:request.FILES 后端获取普通键值对数据:request.POST application/json ajax发送json格式数据 需要注意的点 编码与数据格式要

Django补充——中间件、请求的生命周期等

一:中间件 django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法. 在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图. 与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类 中间件中可以定义四个方法,分别是: pro