1.form组件引入
写一个注册功能
获取用户名密码,利用form表单提交。
在后端判断用户名字和密码是否符合一些条件。
用户名不能含有 xx,密码不能少与三位。
如果符合要求将信息展示到前端页面中。
span行内标签字符有多大则块有多大,空字符则看不出。
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> 注册</ title>
</ head>
< body>
< form action = " " method = " post" >
< p> username:< input type = " text" name = " username" >
< span style = " color : red" > {{ back_dic.username }}</ span>
</ p>
< p> password:< input type = " text" name = " password" >
< span style = " color : red" > {{ back_dic.password }}</ span>
</ p>
< input type = " submit" class = " btn btn-info" >
</ form>
</ body>
</ html>
def ab_form ( request) :
back_dic = { 'username' : '' , 'password' : '' }
if request. method == 'POST' :
username = request. POST. get( 'username' )
password = request. POST. get( 'password' )
print ( username, password)
if 'xx' in username:
back_dic[ 'username' ] = '名称不符合要求'
if len ( password) < 3 :
back_dic[ 'password' ] = '密码不能少于3位'
return render( request, 'ab_form.html' , locals ( ) )
form主键:
能够完成的以上三部:
1. 获取用户的html代码前端代码, 渲染html代码
2. 后端对获取数据进行校验 数据校验
3. 数据不符要求在前端展示 展示错误提示信息
ps :
数据校验前端可有可无,后端必须有,全端页面的校验功能不完善。
能利用爬虫程序直接绕开全端页面向后端提交数据。
例:
购物网站
选中货物之后会计算价格发送给后端,价格的值可能被篡改,如果后端不做价格校验···
实际中获取到用户选择的商品的主键值,后端查询到的价格后在计算一此
如果前后端计算结果一致,完成支付,否则直接拒绝。
一般会进行前后端双重验证,保险、
2.forms组件
from django import forms
class MaForm ( forms. Form) :
username = forms. CharField( min_length= 3 , max_length= 8 )
password = forms. CharField( min_length= 3 , max_length= 8 )
email = forms. EmailField( )
2.1检验数据
测试环境的准备,可以自己拷贝代码,也可以使用pycharm的测试环境。
在pycharm Console中测试
from app01 import views
form_obj = views. MaForm( { 'username' : 'kid' , 'password' : 123 , 'email' : '123@qq.com' } )
form_obj. is_valid( )
True
form_obj. cleaned_data
{ 'username' : 'kid' , 'password' : '123' , 'email' : '123@qq.com' }
form_obj. errors
{ }
form_obj = views. MaForm( { 'username' : 'kid' , 'password' : 123 , 'email' : '123@qq.com' , 'hobby' : 'eat' } )
form_obj. is_valid( )
True
form_obj = views. MaForm( { 'username' : 'kid' , 'password' : 123 } )
form_obj. is_valid( )
False
form_obj. errors
{ 'email' : [ 'This field is required.' ] }
form_obj = views. MaForm( { 'username' : 'kid' , 'password' : 123 , 'email' : '12qqom' } )
form_obj. is_valid( )
False
form_obj. cleaned_data
{ 'username' : 'kid' , 'password' : '123' }
form_obj. errors
{ 'email' : [ 'Enter a valid email address.' ] }
2.3渲染标签
forms组件只会渲染获取用户输入的便签(input select radio checkbox )
不会渲染提交按键
url( r'^index/' , views. index)
def index ( request) :
form_obj = MoForm( )
return render( request, 'index.html' , locals ( ) )
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> form组件获取输入</ title>
< script src = " https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js" > </ script>
< link href = " https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel = " stylesheet" >
< script src = " https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js" > </ script>
< script src = " JQuery.js" > </ script>
</ head>
< body>
< form action = " " method = " post" >
< p> 第一种渲染方式:代码书写极少,封装程度太高,不便于后续的拓展,一般情况下只在本地测试使用</ p>
{{ form_obj.as_p }}
< br>
< br>
{{ form_obj.as_ul }}
< br>
< br>
{{ form_obj.as_table}}
< br>
< br>
< p> 第二种渲染方式: 可扩展性强,但书写代码太多</ p>
{{ form_obj.username }}{{ form_obj.password }}
< br>
< br>
< 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>
</ form>
</ body>
</ html>
label属性默认展示的字段首字母大写,也可以自己修改,直接在字段对象加label属性。
email = forms . EmailField ( label = '邮箱' )
form_obj . username . label 获取属性的名称
form_obj . email . label 设置名称获取到 邮箱
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> form组件获取输入</ title>
< script src = " https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js" > </ script>
< link href = " https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel = " stylesheet" >
< script src = " https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js" > </ script>
< script src = " JQuery.js" > </ script>
</ head>
< body>
< form action = " " method = " post" >
< p> 第三种渲染方式:推荐实时。代码简单扩展性高</ p>
{% for form in form_obj %}
< p> {{ form.label }}:{{ form }}</ p>
{% endfor %}
< input type = " submit" class = " btn btn-info" >
</ form>
</ body>
</ html>
2.3渲染错误信息
浏览器会自动帮你检验数据,但是前端的检验能被篡改,
在form标签中添加 novalidate 属性,让浏览器不做校验。
< !DOCTYPE html>
< html lang= "en" >
< head>
< meta charset= "UTF-8" >
< title> form组件获取输入< / title>
< script src= "https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js" > < / script>
< link href= "https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel= "stylesheet" >
< script src= "https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js" > < / script>
< script src= "JQuery.js" > < / script>
< / head>
< body>
< form action= "" method= "post" novalidate>
< p> 第三种渲染方式: 推荐实时。代码简单扩展性高< / p>
{ % for form in form_obj % }
< p> { { form. label } } : { { form } }
< span style= "color: red" > { { form. errors. 0 } } < / span>
< / p>
{
{
{ % endfor % }
< input type = "submit" class = "btn btn-info" >
< / form>
< / body>
< / html>
必备条件 get请求和post传给html的变量名必须一样,公用 ,第一个渲染方式。
forms组件当你数据不合法的情况下,或保存你上次的数据,让你基于之前的结果进行修改。
def index ( request) :
form_obj = MoForm( )
if request. method == 'POST' :
"""
获取数据并检验数据
1. 数据的获取
2. 校验数据需要构造成字典的格式传入才行
request.POST可以看成一个字典
"""
form_obj = MoForm( request. POST)
if form_obj. is_valid( ) :
pass
else :
pass
return render( request, 'index.html' , locals ( ) )
username = forms. CharField( min_length= 3 , max_length= 8 ,
error_messages= {
'min_length' : '用户名码少于3位数' ,
'max_length' : '用户名不能大于8位树数'
} )
password = forms. CharField( min_length= 3 , max_length= 8 ,
error_messages= {
'min_length' : '密码不少少于3位数' ,
'max_length' : '密码不能大于8位数'
} )
email = forms. EmailField( label= '邮箱' ,
error_essages=
{
'invalid' : '邮箱格式不正确' ,
'required' : '邮箱不能为空'
}
)
2.4钩子函数(HOOK)
在特定的节点自动触发完成响应操作。
钩子函数在forms组件中类似于第二道关卡,能够设置自定义校验规则。
在forms组件中有两类钩子
1. 局部钩子
当你需要给某个字段增加校验规则的时候可以使用
2. 全局钩子
当你需要给某多字段增加校验规则的时候可以使用
1. 校验用户名中不能含有 666 只校验username 字段 使用局部钩子
2. 检验密码和确认密码是否一致 校验password confirm 两个字段全局钩子
from django import forms
class MoForm ( forms. Form) :
username = forms. CharField( min_length= 3 , max_length= 8 ,
error_messages= {
'min_length' : '用户名码少于3位数' ,
'max_length' : '用户名不能大于8位树数' ,
'required' : '用户名不能为空'
} )
password = forms. CharField( min_length= 3 , max_length= 8 ,
error_messages= {
'min_length' : '密码不少少于3位数' ,
'max_length' : '密码不能大于8位数' ,
'required' : '密码不能为空'
} )
confirm = forms. CharField( min_length= 3 , max_length= 8 ,
error_messages= {
'min_length' : '密码不少少于3位数' ,
'max_length' : '密码不能大于8位数' ,
'required' : '密码不能为空'
} )
email = forms. EmailField( label= '邮箱' ,
error_messages=
{
'invalid' : '邮箱格式不正确' ,
'required' : '邮箱不能为空'
}
)
def clean_username ( self) :
username = self. cleaned_data. get( 'username' )
if '666' in username:
self. add_error( 'username' , '不能含有666' )
return username
def clean ( self) :
password = self. cleaned_data. get( 'password' )
confirm = self. cleaned_data. get( 'confirm' )
if not confirm == password:
self. add_error( 'confirm' , '两个密码不一致' )
return self. cleaned_data
2.5其他参数
1. 针对不同的类型input修改
text 普通文本(默认)
password 密文
date 日期
···
添加参数
widget = forms . widget . TextTnput ( ) 普通文本
widget = forms . widget . PasswordTnput ( ) 密文
widget = forms . widget . EmailTnput ( ) 密文
2. 字段设置样式 多个属性,空格隔开
widget = forms . widget . TextTnput ( attrs = { 'class' : 'form-control c1 c2' , 'value' : 'kid' } )
label 字段名
error_messages 自定义报错信息
initial 默认值 initial = 'kid' 框内默认展示kid
required 控制字段是否必填 required= False 可以不填
···
from django import forms
class MoForm ( forms. Form) :
username = forms. CharField( min_length= 3 , max_length= 8 ,
initial= 'kid' ,
error_messages= {
'min_length' : '用户名码少于3位数' ,
'max_length' : '用户名不能大于8位树数' ,
'required' : '用户名不能为空'
} ,
widget= forms. widgets. TextInput(
attrs= { 'class' : 'form-control c1 c2' }
)
)
password = forms. CharField( min_length= 3 , max_length= 8 ,
error_messages= {
'min_length' : '密码不少少于3位数' ,
'max_length' : '密码不能大于8位数' ,
'required' : '密码不能为空'
} ,
widget= forms. widgets. PasswordInput( attrs= { 'class' : 'form-control' } )
)
confirm = forms. CharField( min_length= 3 , max_length= 8 ,
error_messages= {
'min_length' : '密码不少少于3位数' ,
'max_length' : '密码不能大于8位数' ,
'required' : '密码不能为空'
} ,
widget= forms. widgets. PasswordInput( attrs= { 'class' : 'form-control' } )
)
gender = forms. ChoiceField(
choices= ( ( 1 , "男" ) , ( 2 , "女" ) , ( 3 , "保密" ) ) ,
label= "性别" ,
initial= 3 ,
widget= forms. widgets. RadioSelect( )
)
hobby1 = forms. ChoiceField(
choices= ( ( 1 , "篮球" ) , ( 2 , "足球" ) , ( 3 , "双色球" ) , ) ,
label= "爱好" ,
initial= 3 ,
widget= forms. widgets. Select( )
)
hobby2 = forms. MultipleChoiceField(
choices= ( ( 1 , "篮球" ) , ( 2 , "足球" ) , ( 3 , "双色球" ) , ) ,
label= "爱好" ,
initial= [ 1 , 3 ] ,
widget= forms. widgets. SelectMultiple( )
)
keep = forms. ChoiceField(
label= "是否记住密码" ,
initial= "checked" ,
widget= forms. widgets. CheckboxInput( )
)
hobby3 = forms. MultipleChoiceField(
choices= ( ( 1 , "篮球" ) , ( 2 , "足球" ) , ( 3 , "双色球" ) , ) ,
label= "爱好" ,
initial= [ 1 , 3 ] ,
widget= forms. widgets. CheckboxSelectMultiple( )
)
email = forms. EmailField( label= '邮箱' ,
error_messages=
{ 'invalid' : '邮箱格式不正确' ,
'required' : '邮箱不能为空' } )
from django. core. validators import RegexValidator
phone = forms. CharField(
validators =
[ RegexValidator( r'^[0-9]+$' , '请输入数字' ) ,
RegexValidator( r'^159[0-9]+$' , '数字必须以159开头' ) ] ,
)
def clean_username ( self) :
username = self. cleaned_data. get( 'username' )
if '666' in username:
self. add_error( 'username' , '不能含有666' )
return username
def clean ( self) :
password = self. cleaned_data. get( 'password' )
confirm = self. cleaned_data. get( 'confirm' )
if not confirm == password:
self. add_error( 'confirm' , '两个密码不一致' )
return self. cleaned_data
3.forms源码
切入点在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
self. is_bound = data is not None or files is not None
@property
def errors ( self) :
"Returns an ErrorDict for the data provided for the form"
if self. _errors is None :
self. full_clean( )
return self. _errors
def full_clean ( self) :
···
self. _clean_fields( )
self. _clean_form( )
self. _post_clean( )