forms组件
forms组件能够完成的事情:
- 渲染标签
- 校验数据
- 展示提示信息
前端数据校验可有可无,后端据校验必须要有
因为可以修改前端的数据,或者利用爬虫程序绕过前端页面直接向后端提交数据
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组件中像第二道关卡,能够自定义校验规则
-
局部钩子
当需要给单个字段增加校验规则时可以使用
-
全局钩子
当需要给多个字段增加校验规则时可以使用
# 局部钩子
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