Django之forms组件
Django之forms组件
校验字段功能
# reg.html
<form action="" method="post">
{% csrf_token %}
<p>用户名<input type="text" name="username"></p>
<p>密码<input type="text" name="password"></p>
<p>确认密码<input type="text" name="pwd"></p>
<p>邮箱<input type="email" name="email"></p>
<p>手机号<input type="text" name="tel"></p>
<input type="submit">
</form># views.reg
from django import forms
class User(forms.Form):
name = forms.CharField(min_length=4)
password = forms.CharField(min_length=4)
pwd = forms.CharField(min_length=4,)
email = forms.EmailField()
tel = forms.CharField()
def reg(request):
if request.method == ‘POST‘:
print(request.POST)
form = User(request.POST) # 传过来的字典键名和forms的字段名要相同 才能实现检验的功能
# 已经校验的form 校验的字段信息会保留if form.is_valid(): # 传过来的键会一 一和User表中的字段进行对应,然后根据规则进行校验 字段可以多不可以少 少了字段或者校验不符 都为false
print(form.cleaned_data) # cleaned_data都为校验forms字段中成功的键值
else:
print(form.cleaned_data)
print(123)
# print(form.errors) # errors是一个字典 键为校验失败的字段名 值为一个列表 列表中存储错误信息
# print(type(form.errors))
# print(type(form.errors.get(‘name‘)))
# print(form.errors.get(‘name‘)[0])
return render(request, ‘reg.html‘, locals())
form = User()
return render(request, ‘reg.html‘, locals())form.is_valid(): 传过来的键会一 一和User表中的字段进行对应,然后根据规则进行校验,字段可以多不可以少,少了字段或者校验不符,值都为false。
forms.cleaned_data 都为校验forms字段中成功的键值。
form.errors 是一个字典,键为校验失败的字段名,值为一个列表,列表中存储字段的错误信息。
渲染标签功能
上面说到,如果想要用forms对字段进行校验,就要求传入的name和自定义的类的字段名相同,但如果我们不想做这种操作怎么办?
forms提供了渲染标签的功能。
渲染方式1
from django import forms
class User(forms.Form): name = forms.CharField(min_length=4, label=‘用户名‘) password = forms.CharField(min_length=4, label=‘密码‘) pwd = forms.CharField(min_length=4, label=‘确认密码‘) email = forms.EmailField(label=‘邮箱‘) tel = forms.CharField(label=‘电话‘)
def reg(request):
if request.method == ‘POST‘:
print(request.POST)
form = User(request.POST) # 传过来的字典键名和forms的字段名要相同 才能实现检验的功能
# 已经校验的form 校验的字段信息会保留
print(form.is_valid())
if form.is_valid(): # 传过来的键 可以多但是不可以少 少了或者错了 都为false
print(form.cleaned_data) # cleaned_data都为校验forms字段中成功的键值
else:
print(form.cleaned_data)
print(123)
# print(form.errors) # errors是一个字典 键为校验失败的字段名 值为一个列表 列表中存储错误信息
# print(type(form.errors))
# print(type(form.errors.get(‘name‘)))
# print(form.errors.get(‘name‘)[0])
return render(request, ‘reg.html‘, locals())
form = User()
return render(request, ‘reg.html‘, locals())我们来分析一下上面的代码,第一次请求网页是get请求,实例化出一个form对象,然后传入模板

当我们提交数据,就会走POST的代码,这时form对象中已经有了各个字段以及各个字段的值。
因此再次渲染模板时,可以直接通过form.字段名得到字段的值,通过forms.字段名.label可以得到字段的label值,从而自定义输入框的名字。
forms.CharField forms.EmailField 默认会宣称成<input type=‘text‘>标签
<div class="container">
<div class="row">
<div class="col-md-6 col-offset-3">
<h3>forms渲染标签方式一</h3>
<form action="" method="post" novalidate="novalidate">
{# novalidate 使表单不会验证表单的输入 直接提交数据#}
{% csrf_token %}
<p>{{form.name.label}}{{ form.name }}</p>
<p>{{form.password.label}}{{ form.password }}</p>
<p>{{form.pwd.label}}{{ form.pwd }}</p>
<p>{{form.email.label}}{{ form.email }}</p>
<p>{{form.tel.label}}{{ form.tel }}</p>
<input type="submit">
</form>
</div>
</div>
</div>渲染方式二
<h3>forms渲染标签方式二</h3>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<p>
<label for="">{{ field.label }}</label>
{{ field }}
</p>
{% endfor %}
</form>第二种直接通过for循环,更加简单。
渲染方式三
<h3>渲染方式3</h3>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
</form>渲染方式三虽然特别简单,但是不推荐使用,因为这种方式把格式给定死了,当你想要做一些修改的时候不能进行操作。
渲染错误信息
<form action="" method="post" novalidate="novalidate">
{# novalidate 使表单不会验证表单的输入 直接提交数据#}
{% csrf_token %}
<p>{{form.name.label}}{{ form.name }}<span class="pull-right error">{{ form.name.errors.0 }}</span></p>
<p>{{form.password.label}}{{ form.password }}<span class="pull-right error">{{ form.password.errors.0 }}</span></p>
<p>{{form.pwd.label}}{{ form.pwd }}<span class="pull-right error">{{ form.pwd.errors.0 }}</span><span class="pull-right error">{{ errors.0}}</span></p>
<p>{{form.email.label}}{{ form.email }}<span class="pull-right error">{{ form.email.errors.0 }}</span></p>
<p>{{form.tel.label}}{{ form.tel }}<span class="pull-right error">{{ form.tel.errors.0 }}</span></p>
<input type="submit">
</form>视图函数仍为上面的函数,第一次请求渲染出页面,第二次做字段校验时,错误的字段会放入forms.errors中,各个字段的错误信息可通过form.字段名.errors.0取出。
如果没有错误,模板语法不会报错,只是什么都不显示;如果有错误,就将错误显示在输入框后。
显示出来的错误信息是Django内部自己定义好的,如果想要自己定义错误信息,可在User表的每一个字段增加error_message属性
error_messages={‘required‘: ‘该字段不能为空‘, ‘invalid‘:‘输入格式错误‘} 第一个是输入为空时显示的错误信息,第二个是校验不合法时提示的错误信息。
注:forms默认每一个字段不能为空。
forms组件的一些其他参数配置
我们上面定义User类的时候用的是CharField和EmailField,渲染出来的分别是<input type=‘text‘>和<input type=‘email‘>,如果想要改变渲染的类型,或者想给渲染的标签增加一些属性该怎么做呢?
from django import forms
from django.forms import widgets
class User(forms.Form):
name = forms.CharField(min_length=4, label=‘用户名‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
password = forms.CharField(min_length=4, label=‘密码‘, widget=widgets.PasswordInput(attrs={‘class‘:‘form-control‘}), error_messages={‘required‘: ‘该字段不能为空‘})
pwd = forms.CharField(min_length=4, label=‘确认密码‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
email = forms.EmailField(label=‘邮箱‘, error_messages={‘required‘: ‘该字段不能为空‘, ‘invalid‘:‘输入格式错误‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
tel = forms.CharField(label=‘电话‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))通过widget参数可以指定渲染出来的标签类型,同时给标签增加属性。
局部钩子和全局钩子
前面实现的校验功能都是一些非常简单的功能,比如最小长度,邮箱格式。
我们想要实现的目标是可以自定义一些更加复杂的规则,实现一些更加复杂的校验。
from django.shortcuts import render,HttpResponse
# Create your views here.
from django import forms
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class User(forms.Form):
name = forms.CharField(min_length=4, label=‘用户名‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
password = forms.CharField(min_length=4, label=‘密码‘, widget=widgets.PasswordInput(attrs={‘class‘:‘form-control‘}), error_messages={‘required‘: ‘该字段不能为空‘})
pwd = forms.CharField(min_length=4, label=‘确认密码‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
email = forms.EmailField(label=‘邮箱‘, error_messages={‘required‘: ‘该字段不能为空‘, ‘invalid‘:‘输入格式错误‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
tel = forms.CharField(label=‘电话‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
def clean_tel(self):
val = self.cleaned_data.get(‘tel‘)
if len(val) == 11:
return val # 通过正常返回值
else:
raise ValidationError(‘手机号码格式错误‘) #不通过抛出异常
def clean_password(self):
val = self.cleaned_data.get(‘password‘)
if len(val) >=4 :
return val
else:
raise ValidationError(‘手机号码不能小于四位‘)
def clean(self):
password = self.cleaned_data.get(‘password‘)
pwd = self.cleaned_data.get(‘pwd‘)
if password: # password没有通过第一次校验 只抛出第一次校验的错误
if password == pwd:
return self.cleaned_data
else:
raise ValidationError(‘两次密码不一致‘)
else:
return self.cleaned_data
def reg(request):
if request.method == ‘POST‘:
print(request.POST)
form = User(request.POST) # 传过来的字典键名和forms的字段名要相同 才能实现检验的功能
# 已经校验的form 校验的字段信息会保留
print(form.is_valid())
if form.is_valid(): # 传过来的键 可以多但是不可以少 少了或者错了 都为false
print(form.cleaned_data) # cleaned_data都为校验forms字段中成功的键值
else:
print(form.cleaned_data)
print(123)
# print(form.errors) # errors是一个字典 键为校验失败的字段名 值为一个列表 列表中存储错误信息
# print(type(form.errors))
# print(type(form.errors.get(‘name‘)))
# print(form.errors.get(‘name‘)[0])
errors = form.errors.get(‘__all__‘) # 全局钩子错误
return render(request, ‘reg.html‘, locals())
form = User()
return render(request, ‘reg.html‘, locals())通过在类中定义 clean_字段名 的方法,可以实现对字段的自定义校验,成为局部钩子。
通过定义clean方法,可以对多个字段之间进行相互校验,clean方法的校验在局部钩子之后,成为全局钩子。
方法中的返回值和抛出的异常可以参考源码。
局部钩子的字段校验错误,错误信息会放在forms.errors中,键值为字段名,键值为错误信息。
全局钩子的字段校验错误,错误信息也放在forms.error中,键值为‘__all__‘,键值为错误信息。