为什么用form组件
利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。
与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。
Django form组件就实现了上面所述的功能。
总结一下,其实form组件的主要功能如下:
- 1.渲染前端页面
- 2.校验数据是否合法
- 3.展示错误信息
使用form组件
<1> 写一个继承了forms.Form的类
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(max_length=8,min_length=3) # 用户名最长八位最短三位
password = forms.CharField(max_length=8,min_length=5) # 密码最长八位最短五位
email = forms.EmailField() # email必须是邮箱格式
# 主动抛出错误
if username == 'admin':
raise forms.ValidationError(_("Internal Server Error"))
#ps: 类中的username,password...字段,渲染到前端就是获取用户输入的input标签
注意: 类中的字段,如 username,password 一定要与数据库中的字段名字相同
<2>基本使用
# 在Python Console校验
1.将需要校验的数据,以字典的方式传递给自定义的类,实例化产生对象
form_obj = views.LoginForm({'username':'xionger','password':'123','email':'123'})
2.查看数据是否全部合法
form_obj.is_valid() >>> False # 只有所有的数据都符合要求 才会是True
3.查看错误的字段及原因
form_obj.errors # 返回的是字典{字段名:[错误信息],...}
{
'password': ['Ensure this value has at least 5 characters (it has 3).'],
'email': ['Enter a valid email address.']
} # 注意: 对象.errors 拿到的是左右错误字段的字典
4.查看校验合格的字段数据
form_obj.cleaned_data # 返回的是字典{字段名:值,...}
{'username': 'xionger'}
注意:
- 1.自定义类中所有的字段默认都是必须要传值的
- 2.可以额外传入类中没有定义的字段名,form组件不会去校验,也就意味着多传一点关系没有
form_obj = views.LoginForm({'username':'xionger','password':'123456','email':'123@qq.com'})
form_obj.is_valid()
True
form_obj = views.LoginForm({'username':'xionger','password':'123456'})
form_obj.is_valid()
False # 少一个字段
form_obj = views.LoginForm({'username':'xionger','password':'123456','email':'123@qq.com','hobby':'read'})
form_obj.is_valid()
True # 多出的字段不进行校验
<3>渲染页面
三种方式
<p>第一种渲染页面的方式(封装程度太高 一般只用于本地测试 通常不适用)</p>
{{ from_obj }}
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
<p>第二种渲染页面的方式(可扩展性较高 书写麻烦)</p>
<p>{{ form_obj.username.label }}{{ form_obj.username }}</p>
<p>{{ form_obj.password.label }}{{ form_obj.password }}</p>
<p>{{ form_obj.email.label }}{{ form_obj.email }}</p>
<p>第三种渲染页面的方式(推荐)</p>
{% for foo in form_obj %}
<p>{{ foo.label }}{{ foo }}</p>
{% endfor %}
<!--
form_obj 是LoginForm类的对象
form_obj.username 是 字段forms.CharField类的对象 也就是获取用户输入的input标签
form_obj.username.label 是对象 form_obj.username 的属性
foo == form_obj.username
foo.label == form_obj.username.label
-->
注意:
- 1.forms组件在帮你渲染页面的时候,只会渲染获取用户输入的标签,提交按钮需要你手动添加
- 2.input框的label注释,不指定的情况下,默认用的类中字段的首字母大写
<4>展示错误信息
<!--前端-->
{% for foo in form_obj %}
<p>{{ foo.label }}{{ foo }}
<span>{{ foo.errors.0 }}</span> <!--foo.errors是错误的字段列表信息 如:['Enter a valid email address.'] 通过索引0取出内容-->
</p>
{% endfor %}
# 后端
def reg(request):
# 1 现生成一个空的自定义类的对象
form_obj = LoginForm()
# 2 将该对象传递给前端页面
if request.method == 'POST':
# 3 获取前端post请求提交过来的数据
# print(request.POST) # 由于request.POST其实也是一个字典,所以可以直接传给LoginForm
form_obj = LoginForm(request.POST)
# 4 校验数据 让forms组件帮你去校验
if form_obj.is_valid():
# 5 如果数据全部通过 应该写入数据库
user_obj = models.User.objects.create(**form_obj.cleaned_data)
# 6 如果不通过 前端展示错误信息, 将form_obj返回给前端,前端通过form_obj.error[0]拿到错误信息
# 也可以额外添加错误信息
form_obj.errors['freeze_account'] = _("User does not exist.")
return render(request,'reg.html',locals())
<5>钩子函数(HOOK)
forms组件暴露给用户可以自定义的校验规则
用法:在自定义的form类中书写方法即可
- 局部钩子
clean_字段名 :针对某一个字段做额外的校验
def clean_username(self):
# 需要额外校验的字段
username = self.cleaned_data.get('username')
if '666' in username:
# 添加提示的错误信息
self.add_error('username', '用户名不能有666')
# 将字段返回
return username
- 全局钩子
clean : 针对多个字段做额外的校验
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','两次密码不一致')
# 与局部钩子不同,这里需要将 cleaned_data 返回
return self.cleaned_data
form组件其他字段及操作方式:
required 是否必填
label 注释信息
error_messages 报错信息
initial 默认值
widget 控制标签属性和样式
widget=widgets.PasswordInput(attrs={'class':'form-control c1 c2'}) # 改成密文,添加样式
其他字段了解知识点(知道有这些对象 需要用到的时候 能够知道去哪找)
# 单选的radio框
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3, # 默认选择
widget=forms.widgets.RadioSelect()
)
# # 单选select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
# # 多选的select框
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
# 单选的checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
# 多选的checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
# 正则
phone = forms.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
Form所有内置字段: https://www.cnblogs.com/xiaoyuanqujing/protected/articles/11753466.html
推荐文章 https://blog.csdn.net/xgy123xx/article/details/82722185