forms组件

forms组件

当我们比如在注册页面的时候,获取用户输入的用户名、密码或邮箱是否符合我们设置的规则,比如设置密码长度,当不足的时候会提示信息

后端代码:

def register(request):
    # 定义错误信息空字典
    error_dict = {'username': '', 'password': ''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if '666' in username:
            error_dict['username'] = '光喊666是不行的!!!'
        if not password:
            error_dict['password'] = '密码不能为空!!!'
    return render(request, 'register.html', locals())

前端代码:

<form action="" method="post">
    <p>用户名: 
        <input type="text" name="username"> 
        <span style="color: red">{{ error_dict.username }}</span>
    </p>
    <p>密码: 
        <input type="text" name="password"> 
        <span style="color: red">{{ error_dict.password }}</span>
    </p>
    <input type="submit">
</form>

以上我们做了:

1、手写获取用户输入的前端页面代码    >>> 渲染页面

2、后端获取用户数据并做合法校验       >>> 校验数据

3、将校验之后的结果渲染到前端页面    >>> 展示信息

我们可以通过forms组件来帮我们做这些事

总结一下,其实form组件的主要功能如下:

  • 生成页面可用的HTML标签
  • 对用户提交的数据进行校验
  • 保留上次输入内容

1、先写一个类

from django import forms
class MyForms(forms.Form):
    # 用户名最大8位,最少2位,错误提示信息,允许为空,默认值
    username = forms.CharField(max_length=8, min_length=2,
                               error_messages={
                                   'max_length': '用户名最长8位',
                                   'min_length': '用户名最短2位',
                               }, required=False, initial='shen')
    # 密码必须最少3位最多8位,且标签名是密码,控制type属性为password
    password = forms.CharField(max_length=8, min_length=3, label='密码:',
                               widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}))
    # 必须邮箱格式
    email = forms.EmailField(error_messages={
        'required': '邮箱必填',
        'invalid': '邮箱格式不正确'
    })
    # 引用模块validators中RexValidator进行正则校验
    phone = forms.CharField(
        validators=[
            RegexValidator(r'^[0-9]+$', '请输入数字')
        ]
    )

常用的参数:

        label               input的提示信息
        error_messages      自定义报错的提示信息
        required            设置字段是否允许为空,允许为空改为False
        initial             设置默认值
        widget              控制type类型及属性
            widget=forms.widgets.TextInput(attrs={'class':'form-control c1  c2'})
            widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
        validators          正则校验
             validators=[
            RegexValidator(r'^[0-9]+$', '请输入数字')
        ]

其他字段及参数 

# 单选
    gender = forms.ChoiceField(
        choices=((1, ""), (2, ""), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )
    # 单选下拉框
    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )
    # 多选
    hobby1 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
    # 单选
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )
    # 多选
    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )
其他字段及参数

2、后端校验数据

def reg(request):
    # 先生成一个空的类的对象
    form_obj = MyForms()
    if request.method == 'POST':
        # 获取用户数据并交给forms组件校验  request.POST
        # 此处form_obj与上面定义的空对象要相同
        form_obj = MyForms(request.POST)
        # 获取校验结果
        if form_obj.is_valid():
            return HttpResponse('数据没问题')
        else:
            # 获取校验失败的字段和提示信息
            print(form_obj.errors)
    # 直接将该对象传给前端页面
    return render(request, 'reg.html', locals())

校验数据的方法:

1、将数据字典传入我们写的类中

form_obj = MyForms({'username':'shen', 'password': '11', 'email': '111', 'phone': '1234'})

2、判断数据是否符合校验规则

form_obj.is_valid()
# 该方法得到结果只有True和False,只有全部通过校验才会返回True

3、获取哪些数据是校验通过的

form_obj.cleaned_data

4、获取哪些数据是校验失败的,和失败原因

form_obj.errors

5、注意:forms组件所有的字段都必须要传参,不能少了,但是传多了没事,多传的会自动忽略

form_obj = views.MyRegForm({'username':'jason','password':'123456','phone':'11213'})
            form_obj.is_valid()
            # False
            form_obj.errors
            # {'email': ['This field is required.']}
​
form_obj=views.MyRegForm({'username':'jason','password':'123456',"email":'123@qq.com',"hobby":'hahahaha'})
            form_obj.is_valid()
            # True
            form_obj.cleaned_data
            # {'username': 'jason', 'password': '123456', 'email': '123@qq.com'}
            form_obj.errors
            # {}

3、在前端渲染页面

校验数据前后端都应该要有的,但是前端的校验弱不禁风容易被修改,所以后端的校验必须要非常全面

如何取消前端浏览器帮我们做的自动校验功能:利用form表单中的 novalidate

<form action="" method="post" novalidate>

form组件会帮你在前端渲染用户的输入(选择,输入,下拉,文件)的标签,不会渲染按钮,并且渲染出的默认提示信息都是类中的字段首字母大写

三种渲染方式:

{#第一种渲染方式  本地测试方便,封装程度很高,扩展性低#}
<form action="" method="post">
    {{ form_obj.as_p }}   每一个input框都是p标签
    {{ form_obj.as_table }}   按照表格渲染一行展示
    {{ form_obj.as_ul }}   按照无序列表渲染展示
    <input type="submit">
</form>
{#第二种渲染方式  扩展性高,但是书写太繁琐#}
<form action="" method="post">
{#    给username添加label标签和id#}
    <label for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
{{ form_obj.username }}
{#    获取标签的展示信息           获取标签input框#}
{{ form_obj.password.label }} {{ form_obj.password }}
{{ form_obj.email.label }}: {{ form_obj.email }}
{{ form_obj.phone.label }}: {{ form_obj.phone }}
    <input type="submit">
</form>
{#第三种渲染方式  推荐使用#}
<form action="" method="post" novalidate>
{#    循环取出没一个字段#}
    {% for form in form_obj %}
        <p>
{#        字段展示提示信息    字段input框#}
        {{ form.label }} {{ form }}
{#            渲染错误提示信息#}
    <span>{{ form.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit">
</form>

4、钩子函数

实现自定义的校验功能,在自定义类下使用钩子函数

1、全局钩子

在form类中使用 clean() 方法,实现同时对多个字段进行操作

    # 定义全局钩子来校验两次密码是否相同
    # 定义全局钩子,必须是clean
    def clean(self):
        # 获取字段对应的数据
        password = self.cleaned_data.get('password')
        repassword = self.cleaned_data.get('repassword')
        if not password == repassword:
            # 添加错误提示到repassword字段中的错误信息中
            self.add_error('repassword', '两次密码不一样!!!')
        # 返回拿到的全局数据
        return self.cleaned_data

2、局部钩子

在form类中使用 clean_字段名() 方法,实现对某一个字段的校验

    # 定义局部钩子校验用户名中不能有GG
    def clean_username(self):
        # 获取局部定义钩子操作的字段数据
        username = self.cleaned_data.get('username')
        if 'GG' in username:
            # 添加错误信息到username错误信息中
            self.add_error('username', 'GG是不行的')
        # 返回拿到的局部钩子字段
        return username

 

总结:如果想同时操作多个字段的数据就用全局钩子,如果想操作单个字段的数据,就用局部钩子

 

posted @ 2020-01-13 20:42  Mr沈  阅读(168)  评论(0编辑  收藏  举报