• Django Form组件


    Django Form组件

    查看源图像

    简介

    Django Form 组件有两大功能,用于对页面进行初始化,生成 HTML 标签,此外还可以对用户提交对数据进行校验(显示错误信息)

    • 数据重置
    • 校验规则

    form组件和传统form表单对比

    • 当我们用传统的form表单提交时会刷新页面,如果这个我们表单中的某项填错了,刷新后我们正确的选项也没有了
    • 传统的form表单需要我们自己亲自校验每一项,其工作量太大
    • form组件前端自动生成表单元素
    • form组件可自动验证表单内容信息
    • form组件可保留用户上次输入的信息

    导入form django import froms

    校验字段

    ps:这里数据量较小使用sqlite3

    # settings.py需要修改的配置
    # LANGUAGE_CODE = 'en-us'
    LANGUAGE_CODE = 'zh-Hans'  # 修改成中文
    
    # TIME_ZONE = 'UTC'
    TIME_ZONE = 'Asia/Shanghai'   # 时间使用上海的
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = False    # 改为当前时区,默认为True
    
    

    校验字段实操#

    我们在不使用forms的情况下也可以校验用户注册的字段长度是否符合标准,比如通过len()等方法,但是过于麻烦,下面通过forms来校验用户字段长度;(注册举例)

    '''
    1.注册页面,forms校验,需要定义一个类,来继承forms.Form
    2.自定义类内规定的字段就是校验规则
    3.实例化类,得到form对象,使用is_valid校验,校验成功可以通过对象.cleanded.data获取到干净的数据,校验失败通过对象.erros返回错误信息
    '''
    需要注意的是,实例化对象要传入校验数据!
    eg:reg_obj = Reg(data=request.POST)
    
    '''Myforms.py'''
    from django import forms
    
    class Register(forms.Form):
        username = forms.CharField(max_length=8, min_length=3, label='用户名',error_messages={'min_length':'太短了',"required": "该字段不能为空!"})  
        password = forms.CharField(max_length=11, min_length=3, label='密码')
        re_password = forms.CharField(max_length=11, min_length=3, label='确认密码')
        email = forms.EmailField(label='邮箱')
    
    • label:输入框前面的文本信息。
    • error_message:自定义显示的错误信息,属性值是字典, 其中 required 为设置不能为空时显示的错误信息的 key
    '''views.py'''
    from django.shortcuts import render,HttpResponse,redirect
    from app01.My_forms import Register
    
    def register(request):
        if request.method == 'GET':
            return render(request,'register.html')
        else:
            # 实例化,传入校验数据
            reg_form_obj = Register(data=request.POST)
            # 判断校验是否可以通过
            if reg_form_obj.is_valid():
                # 校验通过存入数据库
                print('校验通过')
                print(reg_form_obj.cleaned_data)
                reg_form_obj.cleaned_data.pop('re_password')
                data = reg_form_obj.cleaned_data
                models.Register.objects.create(**data)
    			# 将校验通过的数据打散传入
            else:
                # 校验不通过,返回错误信息
                print('校验不通过')
                print(reg_form_obj.errors)
        return HttpResponse('ok')
    
    '''不理解打散可以看下面这几个示例'''
    	# 字符串打散
        s = 'Hammer'
        print(s) # Hammer
        print(*s) # H a m m e r
        # 元组打散
        tup = (1,2,3) 
        print(tup) # (1, 2, 3)
        print(*tup) # 1 2 3
        # 列表打散
        lst = [1,2,3]
        print(lst) # [1, 2, 3]
        print(*lst) # 1 2 3
        # 字典打散
        def func(name,age):
            print(name,age)
        dic = {'name':'Hammer','age':18}
        func(**dic) # Hammer 18    
    
    '''urls.py'''
    path('register/', views.register)
    
    '''models.py'''
    from django.db import models
    
    class Register(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=32)
        email = models.EmailField
    
    <!--register.html-->
    <form action="" method="post">
        <div class="container">
            <h1 class="active" style="text-align: center">注册页面</h1>
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <p>用户名: <input type="text" name="username" class="form-control"></p>
                    <p>密码: <input type="password" name="password" class="form-control"></p>
                    <p>确认密码: <input type="password" name="re_password" class="form-control"></p>
                    <p>邮箱: <input type="email" name="email" class="form-control"></p>
                    <input type="submit" value="提交" class="btn btn-block btn-info">
                </div>
            </div>
        </div>
    </form>
    
    # 校验不通过
    校验不通过
    <ul class="errorlist"><li>username<ul class="errorlist"><li>该字段不能为空!</li></ul></li></ul>
    
    # 校验通过
    校验通过
    {'username': 'HammerZe', 'password': '123', 're_password': '123', 'email': '456@qq.com'}
    

    forms渲染标签

    自己手动写HTML页面#

    <form action="" method="post">
        <div class="container">
            <h1 class="active" style="text-align: center">注册页面</h1>
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <p>用户名: <input type="text" name="username" class="form-control"></p>
                    <p>密码: <input type="password" name="password" class="form-control"></p>
                    <p>确认密码: <input type="password" name="re_password" class="form-control"></p>
                    <p>邮箱: <input type="email" name="email" class="form-control"></p>
                    <input type="submit" value="提交" class="btn btn-block btn-info">
                </div>
            </div>
        </div>
    </form>
    

    forms渲染标签(一)#

    通过在视图函数中生成一个空form对象,html页面可以直接使用该对象进行渲染

    def register(request):
        if request.method == 'GET':
            empty_form = Register()
            return render(request,'register.html',{'form':empty_form})
        else:
            # 实例化,传入校验数据
            reg_form_obj = Register(data=request.POST)
            # 判断校验是否可以通过
            if reg_form_obj.is_valid():
                # 校验通过存入数据库
                print('校验通过')
                print(reg_form_obj.cleaned_data)
            else:
                # 校验不通过,返回错误信息
                print('校验不通过')
                print(reg_form_obj.errors)
        return HttpResponse('ok')
    
    {#forms渲染标签1#}
    <form action="" method="post">
        <div class="container">
            <h1 class="active" style="text-align: center">注册页面2</h1>
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <p>用户名: {{ form.username }}</p>
                    <p>密码: {{ form.password }}</p>
                    <p>确认密码: {{ form.re_password }}</p>
                    <p>邮箱: {{ form.email }}</p>
                    <input type="submit" value="提交" class="btn btn-block btn-info">
                </div>
            </div>
        </div>
    </form>
    

    总结

    如果使用forms渲染,前端会优化处理,如果长度超出会自动截取等优点

    forms渲染标签(二)【常用】#

    标签页可以通过for循环form对象来渲染,标签前面的字段可以通过label属性来拿到,每循环一次foo就可以得到一个字段

    {#forms渲染标签2#}
    <form action="" method="post">
        <div class="container">
            <h1 class="active" style="text-align: center">注册页面3</h1>
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    {% for foo in form %}
                        <p>{{ foo.label }}:{{ foo }}</p>
                    {% endfor %}
                    <input type="submit" value="提交" class="btn btn-block btn-info">
                </div>
            </div>
        </div>
    </form>
    

    forms渲染标签(三)#

    渲染标签也可以通过一句话来渲染,form.as_p,as_后面可以跟不同标签的名字,比如as_table,as_ul····,但是这样渲染标签直接写死,扩展性极低!

    {#forms渲染标签3#}
    <form action="" method="post">
        <div class="container">
            <h1 class="active" style="text-align: center">注册页面4</h1>
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                   {{ form.as_p }}
    				{#{{ form.as_table }}#}
                    <input type="submit" value="提交" class="btn btn-block btn-info">
                </div>
            </div>
        </div>
    </form>
    

    渲染错误信息

    • novalidate参数,form标签中使用,如果添加该参数,不需要校验或者使用自己的校验规则
    • 渲染错误信息需要传入error_messages参数在类中

    error_messages参数中指定的参数类型

    error_messages参数指定错误信息类型,以字典的形式指定

    • min_length:不满足最小长度渲染的信息
    • max_length:超过最大长度渲染的信息
    • required:非空,必填,如果没填渲染的信息
    • invalid:指定邮箱格式

    示例#

    '''views.py'''
    def register(request):
        if request.method == 'GET':
            empty_form = Register()
            return render(request,'register.html',{'form':empty_form})
        else:
            # 实例化,传入校验数据
            reg_form_obj = Register(data=request.POST)
            # 判断校验是否可以通过
            if reg_form_obj.is_valid():
                # 校验通过存入数据库
                print('校验通过')
                print(reg_form_obj.cleaned_data)
                reg_form_obj.cleaned_data.pop('re_password')
                data = reg_form_obj.cleaned_data
                models.Register.objects.create(**data)
                return HttpResponse('成功')  # 校验通过返回一个成功
            else:
                # 校验不通过,返回错误信息
                print('校验不通过')
                print(reg_form_obj.errors)
                return render(request,'register.html',{'form':reg_form_obj})
            
    

    校验通过和不通过分别返回不同的数据

    <!--前端页面-->
    <form action="" method="post" novalidate>
    <h1 class="active" style="text-align: center">注册页面
      {% for foo in form %}
     <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p>
     {% endfor %}
    <input type="submit" value="提交">
    </form>
    

    需要注意的是,foo.errors返回的是li标签,是多个,想看单个字段的错误信息要指定

    image

    form渲染样式之参数配置

    上面这样直接使用渲染的标签是没有boostrap组件样式的,可以通过在类添加参数来定制样式

    导入from django.forms import widgets

    • widget参数指定input框内的文本格式
    • attrs参数指定标签的样式
    '''Myforms.py'''
    class Register(forms.Form):
        username = forms.CharField(max_length=8, min_length=3, label='用户名',
                                   error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"}
                                   ,widget=widgets.TextInput(attrs={'class':'form-control'}))
        password = forms.CharField(max_length=11, min_length=3, label='密码',widget=widgets.PasswordInput(attrs={'class':'form-control'}))
        re_password = forms.CharField(max_length=11, min_length=3, label='确认密码',widget=widgets.PasswordInput(attrs={'class':'form-control'}))
        email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'},widget=widgets.EmailInput(attrs={'class':'form-control'}))
    
    
    <form action="" method="post" novalidate>
        <div class="container">
            <h1 class="active" style="text-align: center">注册页面3</h1>
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    {% for foo in form %}
                        <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p>
                    {% endfor %}
                    <input type="submit" value="提交" class="btn btn-block btn-info">
                </div>
            </div>
        </div>
    </form>
    

    image

    forms组件全局钩子和局部勾子

    局部钩子使forms校验更加精准,比如限制字段长度,是否为数字等···

    全局钩子可以拿到部分字段进行比较,比如确认两次输入的密码是否一致,或者两次的内容是否一致等···

    局部钩子#

    from django import forms
    from django.core.exceptions import ValidationError
    from django.forms import widgets
    
    
    class Register(forms.Form):
        username = forms.CharField(max_length=8, min_length=3, label='用户名',
                                   error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"}
                                   , widget=widgets.TextInput(attrs={'class': 'form-control'}))
        password = forms.CharField(max_length=11, min_length=3, label='密码',
                                   widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
        re_password = forms.CharField(max_length=11, min_length=3, label='确认密码',
                                      widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
        email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'},
                                 widget=widgets.EmailInput(attrs={'class': 'form-control'}))
    
        def clean_username(self):  # 局部钩子
            # 校验名字不能以sb开头
            username = self.cleaned_data.get('username')
            if username.startswith('sb'):
    
                # 校验不通过,抛出异常
                raise ValidationError('不能以sb开头')
            else:
                return username  # 校验通过,返回username对应的值,这里不返回username值,后面视图函数取不到
    

    总结

    • 抛出异常模块:from django.core.exceptions import ValidationError
    • 局部钩子需要注意的是,自定义函数后面需要加对应字段的名字,比如clean_username,以及校验通过后面要返回校验的字段,不然后面拿不到值

    全局钩子#

    from django import forms
    from django.core.exceptions import ValidationError
    from django.forms import widgets
    
    
    class Register(forms.Form):
        username = forms.CharField(max_length=8, min_length=3, label='用户名',
                                   error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"}
                                   , widget=widgets.TextInput(attrs={'class': 'form-control'}))
        password = forms.CharField(max_length=11, min_length=3, label='密码',
                                   widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
        re_password = forms.CharField(max_length=11, min_length=3, label='确认密码',
                                      widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
        email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'},
                                 widget=widgets.EmailInput(attrs={'class': 'form-control'}))
    
        def clean_username(self):  # 局部钩子
            # 校验名字不能以sb开头
            username = self.cleaned_data.get('username')
            if username.startswith('sb'):
    
                # 校验不通过,抛出异常
                raise ValidationError('不能以sb开头')
            else:
                return username  # 校验通过,返回username对应的值,这里不返回username值,后面视图函数取不到
    
        def clean(self):  # 全局钩子
            password = self.cleaned_data.get('password')
            re_password = self.cleaned_data.get('re_password')
            if password == re_password:
                return self.cleaned_data  # 返回所有校验通过的数据
            else:
                raise ValidationError('两次密码不一致')
    
    from django.shortcuts import render,HttpResponse,redirect
    from app01.My_forms import Register
    from app01 import models
    
    def register(request):
        if request.method == 'GET':
            empty_form = Register()
            return render(request,'register.html',{'form':empty_form})
        else:
            # 实例化,传入校验数据
            reg_form_obj = Register(data=request.POST)
            # 判断校验是否可以通过
            if reg_form_obj.is_valid():
                # 校验通过存入数据库
                print('校验通过')
                print(reg_form_obj.cleaned_data)
                reg_form_obj.cleaned_data.pop('re_password')
                data = reg_form_obj.cleaned_data
                models.Register.objects.create(**data)
                return HttpResponse('成功')  # 校验通过返回一个成功
            else:
                # 校验不通过,返回错误信息
                print('校验不通过')
                print(reg_form_obj.errors)
                global_error = reg_form_obj.errors.get('__all__')[0]  # 全局钩子错误
                # local_error = reg_form_obj.errors.get('username')[0]  # 局部钩子错误
                return render(request,'register.html',{'form':reg_form_obj,'global_error':global_error})
    
    <form action="" method="post" novalidate>
        <div class="container">
            <h1 class="active" style="text-align: center">注册页面3</h1>
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    {% for foo in form %}
                        <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p>
                    {% endfor %}
                    <input type="submit" value="提交" class="btn btn-block btn-info"> <span style="color: #aa100e">{{ global_error }}</span>
                </div>
            </div>
        </div>
    </form>
    

    总结

    • 全局钩子获取错误可以通过__all__获取
    • 渲染标签或者页面要实例化form空对象

    错误信息显示

    报错信息显示顺序:

    • 先显示字段属性中的错误信息,然后再显示局部钩子的错误信息。
    • 若显示了字段属性的错误信息,就不会显示局部钩子的错误信息。
    • 若有全局钩子,则全局钩子是等所有的数据都校验完,才开始进行校验,并且全局钩子的错误信息一定会显示

    image

  • 相关阅读:
    【VUE项目实战】55、商品添加功能(五)-商品内容模块
    linux 合并两个文件夹中的方法
    Python识别图片的文字(Tesseract)和中文分词(jieba)
    双系统安装教程(win10 & ubuntu20.04)
    你安全吗?丨沉默的“复仇”到底是什么东西?
    uniapp 在android手机上运行tab栏页面跳转问题
    idea中引入新JDK环境
    Echarts散点图筛选新玩法dataZoom
    leetcode 92.反转链表II dummy节点的应用
    在 Git 中删除不再位于远程仓库中的本地分支
  • 原文地址:https://www.cnblogs.com/48xz/p/15987602.html