文章目录
1、forms组件1.1、定义1.2、forms校验字段功能1.2.1、定义类,类里写要校验的字段1.2.2、视图函数
1.3、forms渲染模板功能1.3.1、视图函数1.3.2、模板
1.4、forms渲染错误信息1.4.1、视图函数1.4.2、模板
1.5、forms组件参数配置1.6、钩子函数(HOOK)1.6.1、局部钩子1.6.2、全局钩子
2、forms组件校验源码
1、forms组件
1.1、定义
1、注册功能,登录功能,前端需要校验(字段长度,邮箱是否合法…) 2、前端校验可以没有,后端校验是必须的,使用传统方式if判断写的很多 3、借助于forms组件,可以快速实现字段的校验,需要导入:from django.forms import Form
1.2、forms校验字段功能
1.2.1、定义类,类里写要校验的字段
class MyForm(forms
.Form
):
name
= forms
.CharField
(required
=False, max_length
=32, min_length
=3,label
='用户名')
email
= forms
.EmailField
(label
='邮箱')
age
=forms
.IntegerField
(max_value
=130,min_value
=0,label
='年龄')
1.2.2、视图函数
from myforms
import MyForm
def check_user_info(request
):
form
=myforms
.MyForm
(request
.POST
)
if form
.is_valid
():
print('校验通过')
print(form
.cleaned_data
)
else:
print(form
.cleaned_data
)
print(form
.errors
)
print(type(form
.errors
))
print(form
.errors
.as_json
())
print(form
.errors
.as_data
())
return HttpResponse
('ok')
1.3、forms渲染模板功能
1.3.1、视图函数
def check_user_info(request
):
if request
.method
== 'GET':
form
=myforms
.MyForm
()
return render
(request
,'check_user_info.html',{'form': form
})
elif request
.method
== 'POST':
form
=myforms
.MyForm
(request
.POST
)
if form
.is_valid
():
print('校验通过,存数据库')
else:
print(form
.errors
.as_data
())
print('校验失败,返回错误')
return HttpResponse
('ok')
1.3.2、模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title
</title>
</head>
<body>
<hr>
<h1>手动创建模板
</h1>
<form action="" method="post">
<p>用户名:
<input type="text" name="name"></p>
<p>邮箱:
<input type="text" name="email"></p>
<p>年龄:
<input type="text" name="age"></p>
<p><input type="submit" value="提交"></p>
</form>
<h1>半自动渲染模板1
</h1>
<form action="" method="post">
<p>用户名: {{ form.name }}
</p>
<p>邮箱: {{ form.email }}
</p>
<p>年龄: {{ form.age }}
</p>
<p><input type="submit" value="提交"></p>
</form>
<h1>半自动渲染模板2(使用频率高)
</h1>
<form action="" method="post">
<p>{{ form.name.label }}: {{ form.name }}
</p>
<p>{{ form.email.label }}: {{ form.email }}
</p>
<p>{{ form.age.label }}: {{ form.age }}
</p>
<p><input type="submit" value="提交"></p>
</form>
<h1>半自动渲染模板3(使用频率高)
</h1>
<form action="" method="post">
{% for foo in form %}
<p>{{ foo.label }}: {{ foo }}
</p>
{% endfor %}
<p><input type="submit" value="提交"></p>
</form>
<h1>全自动
</h1>
<form action="" method="post">
{{ form.as_ul }}
{{ form.as_p }}
<table>
{{ form.as_table }}
</table>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
1.4、forms渲染错误信息
1.4.1、视图函数
def register(request
):
if request
.method
== 'GET':
form
=myforms
.MyForm
()
return render
(request
, 'register.html',{'form':form
})
else:
form
=myforms
.MyForm
(request
.POST
)
if form
.is_valid
():
return redirect
('http://www.baidu.com')
else:
return render
(request
, 'register.html',{'form':form
})
1.4.2、模板
<form action="" method="post" novalidate>
{% for foo in form %}
<div class="form-group">
<label for="">{{ foo.label }}
</label>
{{ foo }}
<span class="text-danger pull-right">{{ foo.errors }}
</span>
</div>
{% endfor %}
<div class="text-center">
<input type="submit" value="提交" class="btn btn-danger">
</div>
</form>
1.5、forms组件参数配置
定制模板中的显示样式,及配置类
,比如widget
=widgets
.PasswordInput
(attrs
={'class': 'form-control'})
错误信息中文显示,比如error_messages
={'min_length': '字段长度过短'}
from django
.core
.exceptions
import ValidationError
from django
.forms
import widgets
class MyForm(forms
.Form
):
username
= forms
.CharField
(min_length
=3, max_length
=16, label
='用户名',
widget
=widgets
.TextInput
(attrs
={'class': 'form-control'}),
error_messages
={'required': '用户名必传', 'min_length': '用户名至少3位', 'max_lenth': '用户名最多16位'})
age
= forms
.IntegerField
(min_value
=1, max_value
=130, label
='年龄',
widget
=widgets
.TextInput
(attrs
={'class': 'form-control'}), error_messages
={
'required': '年龄必传', 'min_value': '最少1岁', 'max_value': '最大130岁'})
password
= forms
.CharField
(min_length
=3, max_length
=16, label
='密码',
widget
=widgets
.PasswordInput
(attrs
={'class': 'form-control'}))
re_password
= forms
.CharField
(min_length
=3, max_length
=16, label
='确认密码',
widget
=widgets
.PasswordInput
(attrs
={'class': 'form-control'}))
email
= forms
.EmailField
(label
='邮箱', widget
=widgets
.TextInput
(attrs
={'class': 'form-control'}))
text
= forms
.CharField
(label
='个人简介', widget
=widgets
.Textarea
(attrs
={'class': 'form-control'}))
date
= forms
.CharField
(label
='出生日期', widget
=widgets
.DateInput
(attrs
={'class': 'form-control'}))
1.6、钩子函数(HOOK)
在特定的节点自动触发完成响应操作
钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则,钩子函数在类里面书写方法即可
在forms组件中有两类钩子
1、局部钩子
当你需要给单个字段增加校验规则的时候可以使用
2、全局钩子
当你需要给多个字段增加校验规则的时候可以使用
1.6.1、局部钩子
校验用户名中不能含有“xxx”
局部钩子的使用
1、在自定义的Form类中写 clean_字段名
2、取出字段的真正值,name
=self
.cleaned_data
.get
('username')
3、判断自己的规则,如果判断失败,抛出ValidationError或使用self
.add_error
4、如果通过,
return name
def clean_username(self
):
username
= self
.cleaned_data
.get
('username')
if username
.startswith
('xxx'):
self
.add_error
('username', '不能以xxx开头')
else:
return username
1.6.2、全局钩子
校验两次密码填写是否一致
def clean(self
):
password
= self
.cleaned_data
.get
('password')
re_password
= self
.cleaned_data
.get
('re_password')
if password
!= re_password
:
self
.add_error
('re_password', '两次密码不一致')
return self
.cleaned_data
2、forms组件校验源码
1、form_obj
.is_valid
()
def is_valid(self
):
"""
Returns True if the form has no errors. Otherwise, False. If errors are
being ignored, returns False.
"""
return self
.is_bound
and not self
.errors
2、self
.errors
: 这个self指的是BaseForm类
,errors使用了
property修饰
,其实是一个方法
3、self
.full_clean
(): 这个self指的是BaseForm类
4、forms组件所有的功能基本都出自于full_clean方法
def full_clean(self
):
self
._clean_fields
()
self
._clean_form
()
self
._post_clean
()
self
._clean_fields
: 这个self指的是BaseForm类
for name
, field
in self
.fields
.items
():
try:
value
= field
.clean
(value
)
self
.cleaned_data
[name
] = value
if hasattr(self
, 'clean_%s' % name
):
value
= getattr(self
, 'clean_%s' % name
)()
self
.cleaned_data
[name
] = value
except ValidationError
as e
:
self
.add_error
(name
, e
)
self
._clean_form
: 这个self指的是BaseForm类
try:
cleaned_data
= self
.clean
()
except ValidationError
as e
:
self
.add_error
(None, e
)
总结 is_valid() -->self.errors–>self.full_clean() 第一步:self._clean_fields()方法中先会校验form中定义的第一个字段,比如name,然后校验max_lenth,min_length等,校验成功后会查看是否有局部钩子clean_data,如果有就会执行,执行完毕后执行第二步,如果没有直接执行第二步;
第二步:再去校验第二个字段,重复第一步,先校验内置的,再校验局部钩子;
第三步:所有字段都校验通过(字段和局部钩子都成功),校验全局钩子