forms组件

forms组件

forms组件能够完成的事情:

  1. 渲染标签
  2. 校验数据
  3. 展示提示信息

前端数据校验可有可无,后端据校验必须要有

因为可以修改前端的数据,或者利用爬虫程序绕过前端页面直接向后端提交数据

forms组件校验数据

class MyForm(forms.Form):
    username=forms.CharField(min_length=3,max_length=8)
    password=forms.CharField(min_length=3,max_length=8)
    email=forms.EmailField()
    
#在测试环境中校验数据
from app02 import views
# 将待校验的数据组织成字典的形式,只校验类中出现的字段,多传的字段会被忽略
# 默认情况下,类中的所有字段有必须传值
form_obj=views.MyForm({'username':'page','password':123,'email':123})

form_obj.is_valid()
#False,所有数据都合法,才为True

# 拿到合法的数据
form_obj.cleaned_data
'''
{'username': 'page', 'password': '123'}
'''
# 拿到所有不合法的数据,是一个字典,键是字段,值是列表,
form_obj.errors
'''
{'email': ['Enter a valid email address.']}
校验规则可能有多条,违背了一条就向列表中加入一个元素
'''

forms组件渲染标签

forms组件只会渲染获取用户输入的标签,不会渲染提交按钮

<body>
{#    <p>第一种渲染方式,代码量很少,封装程度太高,不便于后续扩展,一般只在本地测试时使用</p>#}
{#    {{ form_obj.as_p }}#}
{#    {{ form_obj.as_ul }}#}
<p>第二种渲染方式,扩展性强</p>
{% for field in form_obj %}
    <p>{{ field.label }}:{{ field }}</p>
{% endfor %}

</body>

class MyForm(forms.Form):
    # 如果没有给label参数传值,那么它的默认值是:字段名(首字母大写)
    username=forms.CharField(min_length=3,max_length=8,label='用户名')
    password=forms.CharField(min_length=3,max_length=8,label='密码')
    email=forms.EmailField(label='邮箱')


def forms(request):
    # 创建空对象
    form_obj=MyForm()

    return render(request,'forms_component.html',locals())

forms组件展示提示信息

如何让浏览器不做校验:novalidate 属性

<form action="" method="post" novalidate>
    
<body>
<form action="" method="post" novalidate>
    {#    <p>第一种渲染方式,代码量很少,封装程度太高,不便于后续扩展,一般只在本地测试时使用</p>#}
{#    {{ form_obj.as_p }}#}
{#    {{ form_obj.as_ul }}#}
<p>第二种渲染方式,扩展性强</p>
{% for field in form_obj %}
    <p>{{ field.label }}:{{ field }}
{#    字段.errors,拿到字段的错误信息列表,.0表示取列表第一个元素#}
    <span  style="color: red">{{ field.errors.0 }}</span>
    </p>
{% endfor %}

<input type="submit" class="btn btn-info">

</form>
</body>
# 自定义错误信息,即给 error_messages参数传值
class MyForm(forms.Form):
        username=forms.CharField(min_length=3,max_length=8,label='用户名',
                                 error_messages={'min_length':'用户名最少三位',
                                                 'max_length':'用户名最多八位',
                                                 'required':'用户名不能为空'})
    password=forms.CharField(min_length=3,max_length=8,label='密码',
                             error_messages={'min_length': '密码最少三位',
                                             'max_length': '密码最多八位',
                                             'required': '密码不能为空'}
                             )
    email=forms.EmailField(label='邮箱',
                           error_messages={
                               'invalid':'邮箱格式不正确',
                               'required': '邮箱不能为空'})


#get请求和post请求传给前端页面的对象变量名必须一样
def forms(request):
    # 创建空对象
    form_obj=MyForm()
    if request.method=='POST':
        # request.POST 可以看成一个大字典,
        form_obj=MyForm(request.POST)
        if form_obj.is_valid():
            return HttpResponse('OK')

    return render(request,'forms_component.html',locals())

form_obj.is_valid()内部起一个for循环,先去校验每个字段配置的规则,校验完成,走字段的局部钩子函数,所有字段都这样校验完了之后,再走全局钩子

forms组件钩子函数

钩子函数在forms组件中像第二道关卡,能够自定义校验规则

  1. 局部钩子

    当需要给单个字段增加校验规则时可以使用

  2. 全局钩子

    当需要给多个字段增加校验规则时可以使用

 # 局部钩子
    def clean_username(self):
        username=self.cleaned_data.get('username')
        # 规则:用户名中不能含有666
        if '666' in username:
            # 给指定字段加提示信息
            self.add_error('username','不能有666')
        # 将钩出来的数据放回去
        return username

    # 全局钩子
    def clean(self):
        password=self.cleaned_data.get('password')
        confirm_password=self.cleaned_data.get('confirm_password')
        if not password==confirm_password:
            self.add_error('confirm_password','两次密码不一致')
        return self.cleaned_data
    
    

forms组件字段其他参数

手机号和身份证号的正则校验,网上有

from django.core.validators import RegexValidator
class MyForm(forms.Form):
    ...
     phone=forms.CharField(validators=[
            RegexValidator('^[0-9]+$','号码必须是数字'),
        ])
initial='jason'	#用来给字段设置默认值
required=False,  #设置:字段不是必填的

widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2'})	#文本输入,给输入框加样式,多个属性值之间用空格隔开
widget=forms.widgets.PasswordInput()	#密文展示
widget=forms.widgets.EmailInput()
    # 单选按钮radio
    gender=forms.ChoiceField(
        choices=((1,'男'),(2,'女'),(3,'保密')),
        label='性别',
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

    # select单选
    hobby = forms.ChoiceField(
        choices=((1, 'study'), (2, 'read'), (3, 'eat')),
        label='爱好',
        initial=3,
        widget=forms.widgets.Select()
    )

    # select多选
    sports = forms.MultipleChoiceField(
        choices=((1, 'running'), (2, 'walk'), (3, 'swimming')),
        label='运动',
        initial=[1,2],
        widget=forms.widgets.SelectMultiple()
    )

    # checkbox单选
    keep = forms.ChoiceField(

        label='是否记住密码',
        initial='checked',
        widget=forms.widgets.CheckboxInput()
    )

    # checkbox多选
    balls = forms.MultipleChoiceField(
        choices=((1, 'football'), (2, 'basketball'), (3, 'volleyball')),
        label='球类',
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

forms组件源码

if hasattr(self, 'clean_%s' % name):
    value = getattr(self, 'clean_%s' % name)()
    self.cleaned_data[name] = value
上一篇:Postman POST请求的四种类型


下一篇:1.22