一、机制流程:

  1、后端接收请求数据。

  2、后端校验数据并封装校验结果发送给前端。

  3、前端根据数据校验结果渲染页面/展示提示信息。

  4、forms组件只会自动渲染获取用户输入的标签(input select radio checkbox)。

二、前端校验与后端校验

  1、前端校验:可靠性比较低,可用可无。

  2、后端校验:比较可靠,必须要有。

三、需要导入的模块

from django import forms
from django.core.validators import RegexValidator  # 正则检验相关

四、实例:

  1、views.py -- class:

class FormDemon(forms.Form):
    username = forms.CharField(
        min_length=3,  # 限制①,长度不得小于3
        max_length=8,  # 限制②,长度不得大于8
        label='用户名:',  # 设置贴签的内容,若不设置,则就用字段名
        initial='tom',  # 设置默认值
        error_messages={  # 设置对应限制不满足时的提示信息,若不设置,则用默认提示样式
            'min_length': '用户名长度不得小于3位',
            'max_length': '用户名长度不得大于8位',
            'required': '用户名不得为空'  # 默认限制,非空
        },
        # 设置<text>形式<input>标签的属性
        widget=forms.widgets.TextInput(
            attrs={'class': 'form-control other_class'}
        )
    )
    password = forms.CharField(
        min_length=3,
        max_length=8,
        label='密码:',
        error_messages={
            'min_length': '密码长度不得小于3位',
            'max_length': '密码长度不得大于8位',
            'required': '密码不得为空'
        },
        # 设置<password>形式<input>标签的属性
        widget=forms.widgets.PasswordInput(
            attrs={'class': 'form-control'}
        )
    )
    re_password = forms.CharField(
        min_length=3,
        max_length=8,
        label='确认密码:',
        error_messages={
            'min_length': '密码长度不得小于3位',
            'max_length': '密码长度不得大于8位',
            'required': '密码不得为空'
        },
        widget=forms.widgets.PasswordInput(
            attrs={'class': 'form-control'}
        )
    )
    email = forms.EmailField(
        label='邮箱(选填):',
        required=False,  # 设置为可为空
        error_messages={
            'invalid': '邮箱格式不正确'  # 邮箱字段的默认限制,必须符合邮箱格式
        },
        # 设置<email>形式<input>标签的属性
        widget=forms.widgets.EmailInput(
            attrs={'class': 'form-control'}
        )
    )
    phone = forms.CharField(
        label='手机号(选填):',
        required=False,
        validators=[
            # 验证手机号的正则匹配式
            # 限定11位,限定1开头,第二位只能是[3,5,6,8,9]中的一个,后9位任意数字
            RegexValidator(r'^[1][3,5,6,8,9][0-9]{9}$', '请输入正确的手机号')
        ],
        widget=forms.widgets.TextInput(
            attrs={'class': 'form-control'}
        )
    )
    gender = forms.ChoiceField(
        choices=(
            (1, ''),
            (2, ''),
            (3, '未知')
        ),
        label='性别:',
        initial=3,
        # 设置<radio>形式<select>标签的属性
        widget=forms.widgets.RadioSelect()
    )
    hobby = forms.ChoiceField(
        choices=(
            (0, '请选择(不选)'),
            (1, '旅游'),
            (2, '电子游戏'),
            (3, '太极拳'),
        ),
        initial=0,
        label='爱好(选填):',
        # 设置单选<select>标签的属性
        widget=forms.widgets.Select()
    )
    skill = forms.MultipleChoiceField(
        choices=(
            (0, '请选择(不选)'),
            (1, '倒立俯卧撑'),
            (2, '三口一头猪'),
            (3, '人体描边术'),
        ),
        initial=[0, ],
        label='特技(选填/可多选):',
        # 设置多选<select>标签的属性
        widget=forms.widgets.SelectMultiple()
    )
    # direct_login = forms.ChoiceField(
    #     label='是否直接登录:',
    #     initial='checked',
    #     # required=False,
    #     # 设置单选<checkbox>标签的属性
    #     widget=forms.widgets.CheckboxInput()
    # )
    channel = forms.MultipleChoiceField(
        choices=(
            (0, '请选择(不选)'),
            (1, '体育'),
            (2, '动漫'),
            (3, '老司机'),
        ),
        initial=[0, ],
        required=False,
        label='感兴趣的频道(选填/可多选):',
        # 设置多选<checkbox>标签的属性
        widget=forms.widgets.CheckboxSelectMultiple()
    )

  2、views.py --- def:

def use_form(request):
    form_obj = FormDemon()  # 先生成一个同名的空的form对象用于初始页面
    if request.method == 'POST':
        form_obj = FormDemon(request.POST)  # 将 request.POST 中的键值对都放入form对象中进行校验
        # 校验准则1:类中定义的字段,除非声明可以为空,否则都需要有值,有错或不全都无法全体合法
        # 校验准则2:多传的未定义的字段会被直接忽略,所以不会被标记为非法,也不会被标记为合法
        if form_obj.is_valid():  # 是否全体合法
            return HttpResponse('信息已上传')
        print('以下是合法部分:')
        print(form_obj.cleaned_data)
        print('以下是非法部分:')
        print(form_obj.errors)
    return render(request, 'form_page.html', locals())

  3、templates:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <script src="{% static 'jQuery351.js' %}"></script>
    <link rel="stylesheet" href="{% static 'Bootstrap337/css/bootstrap.min.css' %}">
    <script src="{% static 'Bootstrap337/js/bootstrap.min.js' %}"></script>
</head>
<body>
<div class="container">
    <p><h1>注册信息</h1></p>
    <form action="" method="post" novalidate>  <!--novalidate(取消浏览器校验)-->
{#        <!--第一种渲染方式,代码很少,封装度高,扩展性差-->#}
{#        {{ form_obj.as_p }}#}
{#        {{ form_obj.as_ul }}#}
{#        {{ form_obj.as_table }}#}
{#        <!--第二种渲染方式,代码较多,扩展性强-->#}
{#        <p>{{ form_obj.username.label }}{{ form_obj.username }}</p>#}
{#        <p>{{ form_obj.password.label }}{{ form_obj.password }}</p>#}
{#        <p>{{ form_obj.re_password.label }}{{ form_obj.re_password }}</p>#}
{#        ...#}
        <!--第三种渲染方式,代码精简,扩展性强-->
        {% for member in form_obj %}
            <p>{{ member.label }}{{ member }}</p>
            <p style="color: red">{{ member.errors.0 }}</p>  <!--调整提示信息样式-->
        {% endfor %}
        <input type="submit" class="btn btn-info" value="提交信息">
    </form>
</div>
</body>
</html>

五、钩子函数:

  1、钩子函数在Forms组件中相当于于再次校验,可以自定义校验规则。

  2、分类:

    ①局部钩子:只能拿出某一个字段进行额外的校验。

    ②全局钩子:可以拿出所有的字段进行任选多个进行额外的校验。

  3、钩子函数在类里面自定。

  4、实例:

    # 局部钩子,指定某一个字段
    def clean_username(self):
        username_again = self.cleaned_data.get('username')  # 已通过第一次校验的才会进行再次校验
        if '4' in username_again:  # 自定义限制
            self.add_error('username', '用户名包含敏感数字')  # 编辑提示信息
        return username_again  # 编辑完放回该字段

    # 全局钩子,可用于所有字段
    def clean(self):
        password_again = self.cleaned_data.get('password')
        re_password_again = self.cleaned_data.get('re_password')
        if password_again != re_password_again:
            self.add_error('re_password', '两次输入的密码不一致')
        return password_again, re_password_again  # 编辑完放回拿出的字段,或直接放回全部字段

 

posted on 2020-05-21 12:01  焚音留香  阅读(136)  评论(0编辑  收藏  举报