python 全栈开发,Day78(Django组件-forms组件)
一、Django组件-forms组件
forms组件
django中的Form组件有以下几个功能:
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容
校验字段功能
之前写的视图函数,提交的数据,没有做校验,就添加到数据库里面了。这样是不对的!
比如:用户名,必须要符合一定的长度。密码复杂度,等等。
forms组件最大的作用,就是做数据校验。
普通做法,一个一个写校验规则,没有解耦。校验规则,都在视图函数里面。
新建项目formDemo
修改urls.py,新增路径index
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), ]
修改views.py,新增index视图函数
form组件先放到视图函数
单独起一个类,后续会分离出来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render# Create your views here.
from django import forms # 必须导入模块
class DemoForm(forms.Form): # 必须继承Form
#限制数据为字符串,最大长度32
name = forms.CharField(max_length=32)
age = forms.IntegerField() # 限制为数字
email = forms.EmailField() # 限制为邮箱格式def index(request):
return render(request,"index.html")
templates新增index.html,里面是空的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body></body>
</html>
打开Pycharm,点击左下角的Django Console
输入以下命令,导入视图函数的DemoForm类
from app01.views import DemoForm
效果如下:
DemoForm类是用来做校验的,它接收一个字典。字典必须包含2个key,分别是name,age,email
测试一个字典数据
执行下面2个命令
form=DemoForm({"name":"xiao","age":"21","email":"123@163.com"}) form.is_valid()
效果如下:输出True
解释:
is_valid()表示执行校验,如果3个key都符合要求,输出True
测试1:age不符合
3个必须同时成立才行
在DemoForm里面,等式左边对应的是key,等式右边对应校验规则
它有一个默认规则,不能为空
测试2:少一个字段
测试3:加一个额外的key-value呢?
从结果上来看,也是可以通过的。
它只校验指定的字段,那么额外的键值,会忽略。
网页校验
修改urls.py,增加路径addbook
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('addbook/', views.addbook), ]
修改views.py,增加addbook视图函数,完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render,HttpResponse# Create your views here.
from django import forms # 必须导入模块
class UserForm(forms.Form): # 必须继承Form
#限制数据为字符串,最小长度4,最大长度12
name = forms.CharField(min_length=4,max_length=12)
age = forms.IntegerField() # 限制为数字
#限制长度为11位
tel = forms.CharField(min_length=11,max_length=11)def index(request):
return render(request,"index.html")def addbook(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
if form.is_valid(): # 验证数据
print("success")
else:
print("fail")
return HttpResponse("ok")</span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">addbook.html</span><span style="color: #800000;">"</span>)</pre>
templates新增addbook.html
做表单校验的时候,一定要注意,表单的name和class的属性必须一一对应
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加用户</h3> <form action="" method="post"> {% csrf_token %} <lable>姓名</lable><input type="text" name="name"/><br/> <lable>年龄</lable><input type="text" name="age"/><br/> <lable>邮箱</lable><input type="text" name="email"/><br/> <lable>手机号码</lable><input type="text" name="tel"/> <br/> <input type="submit"> </form> </body> </html>
网页访问添加页面,输出信息
提交之后,效果如下:
Pycharm控制台输出:success
空表单直接提交
Pycharm控制台输出:fail
is_valid()
form.is_valid() 它做了2件事情:
1.将数据传给form
2.将验证数据拆分到2个容器中
self.cleaned_data= {} 表示干净的数据
self.error = {} 表示验证不通过的数据
self表示UserForm类的实例对象
addbook视图函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def addbook(request): if request.method == "POST": print(request.POST) # 将post数据传给UserForm form = UserForm(request.POST) if form.is_valid(): # 验证数据 print("###success###") print(form.cleaned_data) print(form.errors) else: print("###fail###") print(form.cleaned_data) print(form.errors) print(type(form.errors))</span><span style="color: #0000ff;">return</span> HttpResponse(<span style="color: #800000;">"</span><span style="color: #800000;">ok</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">addbook.html</span><span style="color: #800000;">"</span>)</pre>
再次提交数据
Pycharm控制台输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<QueryDict: {'tel': ['12345678910'], 'email': ['123@qq.com'], 'name': ['xiao'], 'age': ['23'], 'csrfmiddlewaretoken': ['wv7VhRwG4YvEO7SqE9qsMnpO4RpH1ys1KdiOrwgnrN3WRgW0IH8prXSUMCgdMz7u']}> ###success### {'tel': '12345678910', 'age': 23, 'name': 'xiao'}<class 'django.forms.utils.ErrorDict'>
虽然POST发送了5个键值,但是UserForm只校验3个键值。
form.cleaned_data 输出了3个键值
form.errors 输出的内容空,它的类型为ErrorDict
只要有一个错误,就会走else
错误数据演示
修改views.py,修改UserForm,增加邮箱
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class UserForm(forms.Form): # 必须继承Form #限制数据为字符串,最小长度4,最大长度12 name = forms.CharField(min_length=4,max_length=12) age = forms.IntegerField() # 限制为数字 email = forms.EmailField() # 限制为邮箱格式 #限制长度为11位 tel = forms.CharField(min_length=11,max_length=11)
输入一个错误的表单
Pycharm控制台输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
###fail### {'name': 'awew', 'age': 12, 'tel': '12345678910'} <ul class="errorlist"><li>email<ul class="errorlist"><li>Enter a valid email address.</li></ul></li></ul>
form.errors输出了一段Html标签,提示邮箱格式错误
提取email错误信息
修改UserForm
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def addbook(request): if request.method == "POST": # 将post数据传给UserForm form = UserForm(request.POST) print(request.POST) if form.is_valid(): # 验证数据 print("###success###") print(form.cleaned_data) # 所有干净的字段以及对应的值 # ErrorDict : {"校验错误的字段":["错误信息",]} print(form.errors) print(type(form.errors)) # 打印 else: print("###fail###") print(form.cleaned_data) print(form.errors) # 获取email错误信息,返回一个错误列表,可以切片 print(form.errors.get("email")) # 获取第一个错误信息 print(form.errors.get("email")[0])</span><span style="color: #0000ff;">return</span> HttpResponse(<span style="color: #800000;">"</span><span style="color: #800000;">ok</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">addbook.html</span><span style="color: #800000;">"</span>)</pre>
Pycharm控制台输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
###fail### [06/Jul/2018 22:33:41] "POST /addbook/ HTTP/1.1" 200 2 {'tel': '12345678910', 'age': 12, 'name': 'awew'} <ul class="errorlist"><li>email<ul class="errorlist"><li>Enter a valid email address.</li></ul></li></ul> <ul class="errorlist"><li>Enter a valid email address.</li></ul> Enter a valid email address.
form.errors.get("email") 可以提取email的错误信息,它返回的是一个错误列表
通过切片,可以获取第一个错误信息
渲染标签功能
渲染方式1
使用自带的模板属性渲染
上面讲的form表单里面的元素,是手动写的。form组件可以帮你实现渲染表单元素!
那么需要渲染哪些元素,取决于UserForm这个自定义类的属性来决定的
举例:
修改addbook视图函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def addbook(request): if request.method == "POST": # 将post数据传给UserForm form = UserForm(request.POST) print(request.POST) if form.is_valid(): # 验证数据 print("###success###") print(form.cleaned_data) # 所有干净的字段以及对应的值 # ErrorDict : {"校验错误的字段":["错误信息",]} print(form.errors) print(type(form.errors)) # 打印 else: print("###fail###") print(form.cleaned_data) print(form.errors) # 获取email错误信息,返回一个错误列表,可以切片 print(form.errors.get("email")) # 获取第一个错误信息 print(form.errors.get("email")[0])</span><span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span><span style="color: #000000;">:form}) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: form </span>=<span style="color: #000000;"> UserForm() </span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">addbook.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>:form})</pre>
修改addbook.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加用户</h3> <form action="" method="post"> {% csrf_token %} {{ form.as_p }} <br/> <input type="submit"> </form> </body> </html>
as_p是一个特殊的属性,常见的有:
{{ form.as_table }}
以表格的形式将它们渲染在<tr>
标签中{{ form.as_p }}
将它们渲染在<p>
标签中{{ form.as_ul }}
将它们渲染在<li>
标签中
访问页面,效果如下:
使用浏览器工具,查看html代码
它使用了P标签来包裹
lable的for属性和input的id属性是对应的。id的名字和UserForm类定义的属性是类似的,加了id_前缀。
lable的显示的文字和UserForm类定义的属性是一样的,首字母大写了!
input的name属性和UserForm类定义的属性是一样的
默认自带required属性,不允许内容为空。
minlength的属性来源于UserForm类的定义。
注意:form组件只能渲染表单里面的元素,比如input标签。除此之外,其他的需要手写!
它的样式,太丑了!
渲染方式2
使用自定义的标签来包裹form变量
举例:
更改addbook.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加用户</h3> <form action="" method="post"> {% csrf_token %} <div> <p>姓名</p> {{ form.name }} </div> <div> <p>年龄</p> {{ form.age }} </div> <div> <p>邮箱</p> {{ form.email }} </div> <div> <p>手机号码</p> {{ form.tel }} </div> <input type="submit"> </form> </body> </html>
刷新网页,效果如下:
渲染方式3
使用for循环渲染
修改addbook.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加用户</h3> <form action="" method="post"> {% csrf_token %} {% for field in form %} <div> <label for="">{{ field.label }}</label> {{ field }} </div> {% endfor %} <input type="submit"> </form> </body> </html>
刷新网页,效果如下:
field.label 表示UserForm类定义的属性名。注意:它不是html的label标签!
field 表示input输入框,由forms组件渲染
显示中文
将label换成中文,需要增加label属性
修改views.py里面的UserForm类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class UserForm(forms.Form): # 必须继承Form #限制数据为字符串,最小长度4,最大长度12 name = forms.CharField(min_length=4,max_length=12,label="姓名") age = forms.IntegerField(label="年龄") # 限制为数字 email = forms.EmailField(label="邮箱") # 限制为邮箱格式 #限制长度为11位 tel = forms.CharField(min_length=11,max_length=11,label="手机号码")
刷新网页,效果如下:
美化input输入框
需要使用bootstrap
修改urls.py,修改路径
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('adduser/', views.adduser), ]
修改views.py,将addbook重名为adduser
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def adduser(request): if request.method == "POST": # 将post数据传给UserForm form = UserForm(request.POST) print(request.POST) if form.is_valid(): # 验证数据 print("###success###") print(form.cleaned_data) # 所有干净的字段以及对应的值 # ErrorDict : {"校验错误的字段":["错误信息",]} print(form.errors) print(type(form.errors)) # 打印 else: print("###fail###") print(form.cleaned_data) print(form.errors) # 获取email错误信息,返回一个错误列表,可以切片 print(form.errors.get("email")) # 获取第一个错误信息 print(form.errors.get("email")[0])</span><span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span><span style="color: #000000;">:form}) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: form </span>=<span style="color: #000000;"> UserForm() </span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>:form})</pre>
将addbook.html,重命名为adduser.html
引入bootstrap,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body><div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h3>添加用户</h3>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div>
<label for="">{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div></body>
</html>
访问url: http://127.0.0.1:8000/adduser/
效果如下:
这里面input用的还是默认样式,只要给input标签增加class="form-group",就有美化效果!
由于input是form组件渲染的,不能直接添加class,需要在UserForm类里面,指定class
修改UserForm类之前,导入一个模块widgets
Widgets
Widget 是Django 对HTML 输入元素的表示。Widget 负责渲染HTML和提取GET/POST 字典中的数据。
如果你想让某个Widget 实例与其它Widget 看上去不一样,你需要在Widget 对象实例化并赋值给一个表单字段时指定额外的属性(以及可能需要在你的CSS 文件中添加一些规则)
修改views.py,完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render,HttpResponse from django import forms # 必须导入模块 from django.forms import widgets # Create your views here.class UserForm(forms.Form): # 必须继承Form
#定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class":"form-control"})
#限制数据为字符串,最小长度4,最大长度12
name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid)
age = forms.IntegerField(label="年龄",widget=wid) # 限制为数字
# 限制为邮箱格式
email = forms.EmailField(label="邮箱",widget=widgets.EmailInput(attrs={"class":"form-control"}))
#限制长度为11位
tel = forms.CharField(min_length=11,max_length=11,label="手机号码",widget=wid)def index(request):
return render(request,"index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)
print(type(form.errors)) # 打印
else:
print("###fail###")
print(form.cleaned_data)
print(form.errors)
# 获取email错误信息,返回一个错误列表,可以切片
print(form.errors.get("email"))
# 获取第一个错误信息
print(form.errors.get("email")[0])</span><span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span><span style="color: #000000;">:form}) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: form </span>=<span style="color: #000000;"> UserForm() </span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>:form})</pre>
解释:
widget等式右边,可以指定多种类型的输入框,比如:TextInput,EmailInput,DateInput...
默认是TextInput
attrs 表示设置css样式,它接收一个字典,可以写多个css样式!
修改adduser.html
给div增加class="form-group",表示调整上下间距
col-md-offset-2 表示偏移距离
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body><div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
<br/>
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div></body>
</html>
刷新网页,效果如下:
显示错误与保存输入信息功能
保存输入信息功能
比如博客园的注册页面,链接如下:
直接提交空数据,页面会提示
那么form组件,也是可以实现这个效果
修改adduser视图函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def adduser(request): if request.method == "POST": # 将post数据传给UserForm form = UserForm(request.POST) print(request.POST) if form.is_valid(): # 验证数据 print("###success###") print(form.cleaned_data) # 所有干净的字段以及对应的值 # ErrorDict : {"校验错误的字段":["错误信息",]} print(form.errors) print(type(form.errors)) # 打印 # return HttpResponse("添加成功") else: print("###fail###") # print(form.cleaned_data) print(form.errors) # # 获取email错误信息,返回一个错误列表,可以切片 # print(form.errors.get("email")) # # 获取第一个错误信息 # print(form.errors.get("email")[0]) return render(request, "adduser.html") # return render(request, "adduser.html", {"form":form})<span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>:form})</pre>
直接提交空数据,页面有错误提示
注意:这个提示是bootstrap做的,不是form组件
虽然jquery可以直接对表单进行验证,判断为空,或者其他规则。但是客户端浏览器的js代码,是可以跳过验证的。直接提交数据给服务器,如果服务器没有做数据校验,那么将面临风险!
修改adduser.html,在form标签后面增加novalidate,表示关闭bootstrap表单验证
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body><div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
<br/>
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div></body>
</html>
刷新页面,填3个值,最后一个故意不填写
点击提交,效果如下:
发现刚刚增加的数据,没有了。这样用户体验不好!用户得小心翼翼的输入每一个数据!
查看Pycharm控制台输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
###fail### <ul class="errorlist"><li>tel<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
发现它走了else的代码,使用render时,没有传值。导致页面为空!
修改views.py
给adduser.html传一个form。注意:此时的form变量是带有表单数据的!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def adduser(request): if request.method == "POST": # 将post数据传给UserForm form = UserForm(request.POST) print(request.POST) if form.is_valid(): # 验证数据 print("###success###") print(form.cleaned_data) # 所有干净的字段以及对应的值 # ErrorDict : {"校验错误的字段":["错误信息",]} print(form.errors) print(type(form.errors)) # 打印 return HttpResponse("添加成功") else: print("###fail###") # print(form.cleaned_data) print(form.errors) # # 获取email错误信息,返回一个错误列表,可以切片 # print(form.errors.get("email")) # # 获取第一个错误信息 # print(form.errors.get("email")[0]) return render(request, "adduser.html", {"form":form})</span><span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>:form})</pre>
再次刷新页面,数据就回来了!
数据怎么就回来了呢?
因为既然是POST请求,而且携带了POST数据,必然执行了form.is_valid()
虽然没有验证通过,但是执行下面一句代码时
return render(request, "adduser.html", {"form":form})
此时的form是含有POST表单数据的,所以页面才会渲染出来!
注意:当input属性为password时,是不会渲染的!除此之外,其他的表单元素,是可以渲染的!
提交一个正确的数据
提示添加成功
显示错误信息
约定俗成,使用span标签来显示错误信息
修改adduser.html,增加span标签
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body><div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }}<span>{{ field.errors.0 }}</span>
</div>
{% endfor %}
<br/>
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div></body>
</html>
解释:
field.errors 表示错误列表。因为是列表,会有很多错误信息
field.errors.0 表示接收第一个错误信息。一般取第一个即可!
那么问题来了,get请求时,比如地址栏访问页面,它是取不到值的。那么span标签是空的,但是不影响页面展示
直接提交空数据,页面会有英文提示,它表示此字段不允许为空
显示黑色,不好看,加一个样式
修改adduser.html,增加样式。pull-right表示右对齐
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <style> .error { color: red; } </style> </head> <body><div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }}<span class="error pull-right">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<br/>
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div></body>
</html>
刷新页面,效果如下:
错误信息显示中文
显示中文需要在UserForm类中的字段增加error_message属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class UserForm(forms.Form): # 必须继承Form #定义变量,专门给text类型的输入框添加class wid = widgets.TextInput(attrs={"class":"form-control"}) #定义字典,错误信息显示中文 #限制数据为字符串,最小长度4,最大长度12 error_hints = {"required":"该字段不能为空"} name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid,error_messages=error_hints) # 限制为数字 age = forms.IntegerField(label="年龄",widget=wid,error_messages=error_hints) # 限制为邮箱格式 email = forms.EmailField(label="邮箱",widget=widgets.EmailInput(attrs={"class":"form-control"}),error_messages=error_hints) #限制长度为11位 tel = forms.CharField(min_length=11,max_length=11,label="手机号码",widget=wid,error_messages=error_hints)
解释:
error_messages 用来定义错误信息,可以定义多个错误类型!它接收一个字典
required 表示为空时,输出This field is required.
那么要定义中文时,重新赋值即可。需要显示日文,韩文,法文...的,自己定义吧!
重新访问页面,输入第一个值,提交。其它字段会有错误提示!
邮箱输入字符串,提示一段英文信息。不行,得改!
修改UserForm类,修改这一行
error_hints = {"required":"该字段不能为空","invalid":"格式错误!"}
重新提示数据
核心问题,必须要明白,错误信息为什么会显示出来?
执行is_valid(),就会执行校验动作。如果不通过,那么form变量就会包含错误信息。
通过form组件渲染错误信息,页面就展示出来
局部钩子与全局钩子
上面提到的校验规则是forms组件自带的。 它做了一些简单的校验功能,比如判断字符串,纯数字,邮箱等等。
比如要求用户名,必须包含字母和数字。年龄必须要大于18岁,手机号码要以136,137开头...
这些需求,默认的校验规则是做不到的。
我们想要自行设计校验的规则,Django给我们提供了钩子。
先来看一段源码:
if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value
这段源码能够设置钩子的来源。
局部钩子
导入模块
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
举例:
要求用户名不能是纯数字
def clean_name(self): val = self.cleaned_data.get("name") # 获取输入的用户名<span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> val.isdigit(): <span style="color: #008000;">#</span><span style="color: #008000;"> 判断不是数字类型</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名不能是纯数字</span><span style="color: #800000;">"</span>)</pre>
注意:
clean_name 这个名字是有含义的,不能随便定义。name表示UserForm类的属性。clean表示校验
val 表示用户输入的用户名
val.isdigit() 表示判断输入的是否为数字,必须return 一个值
raise 表示主动报错,必须接ValidationError。
上面这些要求是源代码定义的,具体可以看源代码。
views.py,完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render,HttpResponse from django import forms # 必须导入模块 from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationError # Create your views here.class UserForm(forms.Form): # 必须继承Form
#定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class":"form-control"})
#定义字典,错误信息显示中文
#限制数据为字符串,最小长度4,最大长度12
error_hints = {"required":"该字段不能为空","invalid":"格式错误!"}
name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid,error_messages=error_hints)
# 限制为数字
age = forms.IntegerField(label="年龄",widget=wid,error_messages=error_hints)
# 限制为邮箱格式
email = forms.EmailField(label="邮箱",widget=widgets.EmailInput(attrs={"class":"form-control"}),error_messages=error_hints)
#限制长度为11位
tel = forms.CharField(min_length=11,max_length=11,label="手机号码",widget=wid,error_messages=error_hints)</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_name(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">name</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 获取输入的用户名</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> val.isdigit(): <span style="color: #008000;">#</span><span style="color: #008000;"> 判断数字类型</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名不能是纯数字</span><span style="color: #800000;">"</span><span style="color: #000000;">)
def index(request):
return render(request,"index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)
print(type(form.errors)) # 打印
return HttpResponse("添加成功")
else:
print("###fail###")
# print(form.cleaned_data)
print(form.errors)
# # 获取email错误信息,返回一个错误列表,可以切片
# print(form.errors.get("email"))
# # 获取第一个错误信息
# print(form.errors.get("email")[0])
return render(request, "adduser.html", {"form":form})</span><span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>:form})</pre>
验证一下,输入4位数字,提交之后,页面提示如下:
手机号码必须11位
修改UserForm类,增加clean_tel方法,完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render,HttpResponse from django import forms # 必须导入模块 from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationError # Create your views here.class UserForm(forms.Form): # 必须继承Form
#定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class":"form-control"})
#定义字典,错误信息显示中文
#限制数据为字符串,最小长度4,最大长度12
error_hints = {"required":"该字段不能为空","invalid":"格式错误!"}
name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid,error_messages=error_hints)
# 限制为数字
age = forms.IntegerField(label="年龄",widget=wid,error_messages=error_hints)
# 限制为邮箱格式
email = forms.EmailField(label="邮箱",widget=widgets.EmailInput(attrs={"class":"form-control"}),error_messages=error_hints)
#限制长度为11位
tel = forms.CharField(max_length=11,label="手机号码",widget=wid,error_messages=error_hints)</span><span style="color: #0000ff;">def</span> clean_name(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 校验name值</span> val = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">name</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 获取输入的用户名</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> val.isdigit(): <span style="color: #008000;">#</span><span style="color: #008000;"> 判断数字类型</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名不能是纯数字</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_tel(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">tel</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> len(val) == 11: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断长度</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">手机号码必须11位</span><span style="color: #800000;">"</span><span style="color: #000000;">)
def index(request):
return render(request,"index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)
print(type(form.errors)) # 打印
return HttpResponse("添加成功")
else:
print("###fail###")
# print(form.cleaned_data)
print(form.errors)
# # 获取email错误信息,返回一个错误列表,可以切片
# print(form.errors.get("email"))
# # 获取第一个错误信息
# print(form.errors.get("email")[0])
return render(request, "adduser.html", {"form":form})</span><span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>:form})</pre>
注意:要去除tel里面的min_length,这是不严谨的写法!
重新访问页面,测试一下
年龄必须18岁以上
增加clean_age方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def clean_age(self): val = self.cleaned_data.get("age") if int(val) > 18: # input输入的值为字符串,必须转换为int return val else: raise ValidationError("年龄必须满18岁以上!")
重新访问页面,测试一下
注意:
is_valid执行时,才会执行校验。
这里有2层校验。第一层校验是UserForm定义的那些属性,比如判断字符串或者数字的。
第二次校验是clean_属性名 定义的这些方法。只有通过第一层校验时,才会进入第二层校验。
不论式第一层还是第二层,通过校验后,将key_value放到 cleaned_data容器里面。不通过校验时,将key-value放到errors容器里面
查看源代码
先找到views.py里面的is_valid,使用Ctrl+鼠标左键,点击is_valid。它会调转到is_valid方法的源代码
点击self.errors-->full_clean()-->self._clean_fields()
_clean_fields源代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def _clean_fields(self): for name, field in self.fields.items(): # value_from_datadict() gets the data from the data dictionaries. # Each widget type knows how to retrieve its own data, because some # widgets split data over several HTML fields. if field.disabled: value = self.get_initial_for_field(field, name) else: value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) try: if isinstance(field, FileField): initial = self.get_initial_for_field(field, name) value = field.clean(value, initial) else: 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)
它会对表单的每一个数据,使用for循环处理。field指的是UserForm定义的那些属性
self.fields.items() 这里的self.fields数据,可能是这样的。
self.fields={"name":name的field对象,"age":age的field对象...}
self.fields.items() ,就能拿到一个field对象。这个field是是一个规则对象.
self.cleaned_data[name] = value 表示通过第一层校验,将干净的数据放到cleaned_data容器里
if hasattr(self, 'clean_%s' % name): 表示进入第二校验,name表示UserForm定义的那些属性。通过后,也会放到cleaned_data容器里
except ValidationError as e 表示接收ValidationError错误,add_error表示添加到error容器里。
所以在UserForm定义clean时,必须使用raise ValidationError(xxx)
假设通过第一层校验,但是没有通过第二层校验时。它会执行add_error方法,那么原来的cleaned_data容器的数据怎么办?
add_error源代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def add_error(self, field, error): """ Update the content of `self._errors`.The `field` argument is the name of the field to which the errors should be added. If it's None, treat the errors as NON_FIELD_ERRORS. The `error` argument can be a single error, a list of errors, or a dictionary that maps field names to lists of errors. An "error" can be either a simple string or an instance of ValidationError with its message attribute set and a "list or dictionary" can be an actual `list` or `dict` or an instance of ValidationError with its `error_list` or `error_dict` attribute set. If `error` is a dictionary, the `field` argument *must* be None and errors will be added to the fields that correspond to the keys of the dictionary. </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> isinstance(error, ValidationError): </span><span style="color: #008000;">#</span><span style="color: #008000;"> Normalize to ValidationError and let its constructor</span> <span style="color: #008000;">#</span><span style="color: #008000;"> do the hard work of making sense of the input.</span> error =<span style="color: #000000;"> ValidationError(error) </span><span style="color: #0000ff;">if</span> hasattr(error, <span style="color: #800000;">'</span><span style="color: #800000;">error_dict</span><span style="color: #800000;">'</span><span style="color: #000000;">): </span><span style="color: #0000ff;">if</span> field <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> None: </span><span style="color: #0000ff;">raise</span><span style="color: #000000;"> TypeError( </span><span style="color: #800000;">"</span><span style="color: #800000;">The argument `field` must be `None` when the `error` </span><span style="color: #800000;">"</span> <span style="color: #800000;">"</span><span style="color: #800000;">argument contains errors for multiple fields.</span><span style="color: #800000;">"</span><span style="color: #000000;"> ) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: error </span>=<span style="color: #000000;"> error.error_dict </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: error </span>= {field <span style="color: #0000ff;">or</span><span style="color: #000000;"> NON_FIELD_ERRORS: error.error_list} </span><span style="color: #0000ff;">for</span> field, error_list <span style="color: #0000ff;">in</span><span style="color: #000000;"> error.items(): </span><span style="color: #0000ff;">if</span> field <span style="color: #0000ff;">not</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.errors: </span><span style="color: #0000ff;">if</span> field != NON_FIELD_ERRORS <span style="color: #0000ff;">and</span> field <span style="color: #0000ff;">not</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.fields: </span><span style="color: #0000ff;">raise</span><span style="color: #000000;"> ValueError( </span><span style="color: #800000;">"</span><span style="color: #800000;">'%s' has no field named '%s'.</span><span style="color: #800000;">"</span> % (self.<span style="color: #800080;">__class__</span>.<span style="color: #800080;">__name__</span><span style="color: #000000;">, field)) </span><span style="color: #0000ff;">if</span> field ==<span style="color: #000000;"> NON_FIELD_ERRORS: self._errors[field] </span>= self.error_class(error_class=<span style="color: #800000;">'</span><span style="color: #800000;">nonfield</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: self._errors[field] </span>=<span style="color: #000000;"> self.error_class() self._errors[field].extend(error_list) </span><span style="color: #0000ff;">if</span> field <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.cleaned_data: </span><span style="color: #0000ff;">del</span> self.cleaned_data[field]</pre>
注意:看最后一行,它会将cleaned_data容器里,没通过的数据给删除掉!
全局钩子
局部钩子只能校验一个字段,那么2个字段校验呢?比如密码和确认密码必须一致,这个时候,需要使用全局钩子
如何定义全局钩子呢?查看源代码
is_valid()-->self.errors-->self.full_clean()-->self._clean_form()-->self.clean()
clean源代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def clean(self): """ Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named '__all__'. """ return self.cleaned_data
谷歌翻译如下:
在Field.clean()之后进行任何额外的表单范围清理,呼吁每个领域。此方法引发的任何ValidationError都将与特定领域无关;它将有一个特例与名为'__all__'的字段关联。
大概意思就是,它在clean_xx执行之后,才会执行。一旦引发了ValidationError,与特定领域无关。错误信息都在'__all__'里面
这个clean是全局钩子,属于第3层校验规则。源代码没有任何逻辑,所以这个方法,需要我们来重写。注意:名字必须是clean,结尾部分必须是return self.cleaned_data
两次密码不一致
修改UserForm类,增加2个属性,并定义全局钩子clean
完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render, HttpResponse from django import forms # 必须导入模块 from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationError# Create your views here.
class UserForm(forms.Form): # 必须继承Form
# 定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class": "form-control"})
# 定义字典,错误信息显示中文
# 限制数据为字符串,最小长度4,最大长度12
error_hints = {"required": "该字段不能为空", "invalid": "格式错误!"}
name = forms.CharField(min_length=4, max_length=12, label="姓名", widget=wid, error_messages=error_hints)
# 密码字段
pwd = forms.CharField(label="密码", widget=widgets.PasswordInput(attrs={"class": "form-control"}))r_pwd </span>= forms.CharField(label=<span style="color: #800000;">"</span><span style="color: #800000;">确认密码</span><span style="color: #800000;">"</span>, widget=widgets.PasswordInput(attrs={<span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">form-control</span><span style="color: #800000;">"</span><span style="color: #000000;">})) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制为数字</span> age = forms.IntegerField(label=<span style="color: #800000;">"</span><span style="color: #800000;">年龄</span><span style="color: #800000;">"</span>, widget=wid, error_messages=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制为邮箱格式</span> email = forms.EmailField(label=<span style="color: #800000;">"</span><span style="color: #800000;">邮箱</span><span style="color: #800000;">"</span>, widget=widgets.EmailInput(attrs={<span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">form-control</span><span style="color: #800000;">"</span><span style="color: #000000;">}), error_messages</span>=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制长度为11位</span> tel = forms.CharField(max_length=11, label=<span style="color: #800000;">"</span><span style="color: #800000;">手机号码</span><span style="color: #800000;">"</span>, widget=wid, error_messages=<span style="color: #000000;">error_hints) </span><span style="color: #0000ff;">def</span> clean_name(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 校验name值</span> val = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">name</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 获取输入的用户名</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> val.isdigit(): <span style="color: #008000;">#</span><span style="color: #008000;"> 判断数字类型</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名不能是纯数字</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_tel(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">tel</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> len(val) == 11: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断长度</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">手机号码必须11位</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_age(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">age</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> int(val) > 18: <span style="color: #008000;">#</span><span style="color: #008000;"> input输入的值为字符串,必须转换为int</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">年龄必须满18岁以上!</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> clean(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 全局钩子</span> pwd = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) r_pwd </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">r_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> pwd <span style="color: #0000ff;">and</span> r_pwd <span style="color: #0000ff;">and</span> pwd != r_pwd: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断2次密码不为空,并且2次密码不相等</span> <span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">两次密码不一致</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span> self.cleaned_data <span style="color: #008000;">#</span><span style="color: #008000;"> 这句是固定写法,不能变动</span>
def index(request):
return render(request, "index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)
print(type(form.errors)) # 打印
return HttpResponse("添加成功")
else:
print("###fail###")
# print(form.cleaned_data)
print(form.errors)
# # 获取email错误信息,返回一个错误列表,可以切片
# print(form.errors.get("email"))
# # 获取第一个错误信息
# print(form.errors.get("email")[0])
return render(request, "adduser.html", {"form": form})</span><span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>: form})</pre>
重新访问页面,效果如下:
测试2次密码不一致
发现密码没有错误提示,为什么呢?
因为全局钩子和局部钩子不一样,它的错误信息在__all__里面
修改adduser视图函数,完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render, HttpResponse from django import forms # 必须导入模块 from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationError# Create your views here.
class UserForm(forms.Form): # 必须继承Form
# 定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class": "form-control"})
# 定义字典,错误信息显示中文
# 限制数据为字符串,最小长度4,最大长度12
error_hints = {"required": "该字段不能为空", "invalid": "格式错误!"}
name = forms.CharField(min_length=4, max_length=12, label="姓名", widget=wid, error_messages=error_hints)
# 密码字段
pwd = forms.CharField(label="密码", widget=widgets.PasswordInput(attrs={"class": "form-control"}),
error_messages=error_hints)r_pwd </span>= forms.CharField(label=<span style="color: #800000;">"</span><span style="color: #800000;">确认密码</span><span style="color: #800000;">"</span>, widget=widgets.PasswordInput(attrs={<span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">form-control</span><span style="color: #800000;">"</span><span style="color: #000000;">}), error_messages</span>=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制为数字</span> age = forms.IntegerField(label=<span style="color: #800000;">"</span><span style="color: #800000;">年龄</span><span style="color: #800000;">"</span>, widget=wid, error_messages=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制为邮箱格式</span> email = forms.EmailField(label=<span style="color: #800000;">"</span><span style="color: #800000;">邮箱</span><span style="color: #800000;">"</span>, widget=widgets.EmailInput(attrs={<span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">form-control</span><span style="color: #800000;">"</span><span style="color: #000000;">}), error_messages</span>=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制长度为11位</span> tel = forms.CharField(max_length=11, label=<span style="color: #800000;">"</span><span style="color: #800000;">手机号码</span><span style="color: #800000;">"</span>, widget=wid, error_messages=<span style="color: #000000;">error_hints) </span><span style="color: #0000ff;">def</span> clean_name(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 校验name值</span> val = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">name</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 获取输入的用户名</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> val.isdigit(): <span style="color: #008000;">#</span><span style="color: #008000;"> 判断数字类型</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名不能是纯数字</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_tel(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">tel</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> len(val) == 11: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断长度</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">手机号码必须11位</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_age(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">age</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> int(val) > 18: <span style="color: #008000;">#</span><span style="color: #008000;"> input输入的值为字符串,必须转换为int</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">年龄必须满18岁以上!</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> clean(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 全局钩子</span> pwd = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) r_pwd </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">r_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> pwd <span style="color: #0000ff;">and</span> r_pwd <span style="color: #0000ff;">and</span> pwd != r_pwd: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断2次密码不为空,并且2次密码不相等</span> <span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">两次密码不一致</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span> self.cleaned_data <span style="color: #008000;">#</span><span style="color: #008000;"> 这句是固定写法,不能变动</span>
def index(request):
return render(request, "index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)
print(type(form.errors)) # 打印
return HttpResponse("添加成功")
else:
print("###fail###")
# print(form.cleaned_data)
print(form.errors)
# # 获取email错误信息,返回一个错误列表,可以切片
# print(form.errors.get("email"))
# # 获取第一个错误信息
# print(form.errors.get("email")[0])
g_error = form.errors.get("all") # 接收全局钩子错误信息
if g_error: # 判断有错误信息的情况下
g_error = g_error[0] # 取第一个错误信息<span style="color: #008000;">#</span><span style="color: #008000;"> 将form和g_error变量传给adduser.html</span> <span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>: form, <span style="color: #800000;">"</span><span style="color: #800000;">g_error</span><span style="color: #800000;">"</span><span style="color: #000000;">: g_error}) </span><span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>: form})</pre>
修改adduser.html,完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <style> .error { color: red; } </style> </head> <body><div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }} <span class="error pull-right">{{ field.errors.0 }}</span>
{% if field.label == "确认密码" %}
<span class="error pull-right">{{ g_error|default_if_none:"" }}</span>
{% endif %}
</div>
{% endfor %}
<br/>
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div></body>
</html>
解释:
我们想在第二次密码输入框下面,展示全局钩子的错误信息。那么需要用到if判断了
g_error|default_if_none:"" 表示当g_error为none时,页面显示为空("")
验证一下,输入2个不一致的密码
效果如下:
Pycharm控制台输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<QueryDict: {'name': [''], 'r_pwd': ['111'], 'email': [''], 'age': [''], 'pwd': ['11'], 'csrfmiddlewaretoken': ['slo8iY8aB1Z1x6coSPfaqxdrLQW5NSCxG3z1sDSRYQxjAfgYWnX757GxtBNByTh0'], 'tel': ['']}> ###fail### <ul class="errorlist"><li>__all__<ul class="errorlist nonfield"><li>两次密码不一致</li></ul></li><li>name<ul class="errorlist"><li>该字段不能为空</li></ul></li><li>age<ul class="errorlist"><li>该字段不能为空</li></ul></li><li>tel<ul class="errorlist"><li>该字段不能为空</li></ul></li><li>email<ul class="errorlist"><li>该字段不能为空</li></ul></li></ul>
如果只输入了1个密码呢?
页面提示确认密码不能为空
两次密码必须输入时,才会进入全局钩子
这是为什么?此时的UserForm有3层校验规则。执行顺序如下:
forms组件自带的校验规则-->局部钩子-->全局钩子
那么当有一个密码没有输入时,直接被第一层校验规则拦截了,它是不会进入到第三层校验规则的!
设置全局钩子,必然会执行。如果上层报错,那么不会进入全局钩子!
思考问题:forms的校验规则和models.py的模型类,有没有关系?
答案是没有关系!forms可以独立运行,forms组件没有必要,必须和model表的字段一一对应。
根据业务需求,在需要校验的字段上,进行校验!
分离forms代码
在views.py同级目录创建文件form.py,将forms相关代码剪贴过去,完整内容如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django import forms # 必须导入模块 from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationErrorclass UserForm(forms.Form): # 必须继承Form
# 定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class": "form-control"})
# 定义字典,错误信息显示中文
# 限制数据为字符串,最小长度4,最大长度12
error_hints = {"required": "该字段不能为空", "invalid": "格式错误!"}
name = forms.CharField(min_length=4, max_length=12, label="姓名", widget=wid, error_messages=error_hints)
# 密码字段
pwd = forms.CharField(label="密码", widget=widgets.PasswordInput(attrs={"class": "form-control"}),
error_messages=error_hints)r_pwd </span>= forms.CharField(label=<span style="color: #800000;">"</span><span style="color: #800000;">确认密码</span><span style="color: #800000;">"</span>, widget=widgets.PasswordInput(attrs={<span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">form-control</span><span style="color: #800000;">"</span><span style="color: #000000;">}), error_messages</span>=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制为数字</span> age = forms.IntegerField(label=<span style="color: #800000;">"</span><span style="color: #800000;">年龄</span><span style="color: #800000;">"</span>, widget=wid, error_messages=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制为邮箱格式</span> email = forms.EmailField(label=<span style="color: #800000;">"</span><span style="color: #800000;">邮箱</span><span style="color: #800000;">"</span>, widget=widgets.EmailInput(attrs={<span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">form-control</span><span style="color: #800000;">"</span><span style="color: #000000;">}), error_messages</span>=<span style="color: #000000;">error_hints) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 限制长度为11位</span> tel = forms.CharField(max_length=11, label=<span style="color: #800000;">"</span><span style="color: #800000;">手机号码</span><span style="color: #800000;">"</span>, widget=wid, error_messages=<span style="color: #000000;">error_hints) </span><span style="color: #0000ff;">def</span> clean_name(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 校验name值</span> val = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">name</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 获取输入的用户名</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> val.isdigit(): <span style="color: #008000;">#</span><span style="color: #008000;"> 判断数字类型</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名不能是纯数字</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_tel(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">tel</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> len(val) == 11: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断长度</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">手机号码必须11位</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> clean_age(self): val </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">age</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> int(val) > 18: <span style="color: #008000;">#</span><span style="color: #008000;"> input输入的值为字符串,必须转换为int</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> val </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">年龄必须满18岁以上!</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> clean(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 全局钩子</span> pwd = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) r_pwd </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">r_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> pwd <span style="color: #0000ff;">and</span> r_pwd <span style="color: #0000ff;">and</span> pwd != r_pwd: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断2次密码不为空,并且2次密码不相等</span> <span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">两次密码不一致</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span> self.cleaned_data <span style="color: #008000;">#</span><span style="color: #008000;"> 这句是固定写法,不能变动</span></pre>
修改views.py,导入UserForm类,完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render, HttpResponse from app01.form import UserForm # 导入UserForm类# Create your views here.
def index(request):
return render(request, "index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)
print(type(form.errors)) # 打印
return HttpResponse("添加成功")
else:
print("###fail###")
# print(form.cleaned_data)
print(form.errors)
# # 获取email错误信息,返回一个错误列表,可以切片
# print(form.errors.get("email"))
# # 获取第一个错误信息
# print(form.errors.get("email")[0])
g_error = form.errors.get("all") # 接收全局钩子错误信息
if g_error: # 判断有错误信息的情况下
g_error = g_error[0] # 取第一个错误信息<span style="color: #008000;">#</span><span style="color: #008000;"> 将form和g_error变量传给adduser.html</span> <span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>: form, <span style="color: #800000;">"</span><span style="color: #800000;">g_error</span><span style="color: #800000;">"</span><span style="color: #000000;">: g_error}) </span><span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>: form})</pre>
再次访问页面,测试密码不一致
效果如下:
form组件补充知识
Django内置字段
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Field required=True, 是否允许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否可以编辑 label_suffix=None Label内容后缀CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值FloatField(IntegerField)
...DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度BaseTemporalField(Field)
input_formats=None 时间格式化DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12DurationField(Field) 时间间隔:%d %H:%M:%S.%f
...RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}EmailField(CharField)
...FileField(Field)
allow_empty_file=False 是否允许空文件ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)URLField(Field)
...BooleanField(Field)
...NullBooleanField(BooleanField)
...ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceFieldTypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值MultipleChoiceField(ChoiceField)
...TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用SlugField(CharField) 数字,字母,下划线,减号(连字符)
...UUIDField(CharField) uuid类型
...
你可以在里面选择属性的类型以及约束。
Django内置插件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
在witgits中选择使用
常用插件选择
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 单radio,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # )# 单radio,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.RadioSelect
)
# 单select,值为字符串
user = fields.CharField(
initial=2,
widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)
# 单select,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
# 多选select,值为列表
user = fields.MultipleChoiceField(
choices=((1,'上海'),(2,'北京'),),
initial=[1,],
widget=widgets.SelectMultiple
)
# 单checkbox
user = fields.CharField(
widget=widgets.CheckboxInput()
)
# 多选checkbox,值为列表
user = fields.MultipleChoiceField(
initial=[2, ],
choices=((1, '上海'), (2, '北京'),),
widget=widgets.CheckboxSelectMultiple
)
周末作业:
在图书管理系统里,增加一个注册页面
要求:
1.基于forms组件做校验 1.1 用户名不能小于4位,不能是纯数字,用户名不能重复 1.2 密码不能小于6位,不能是纯数字 1.3 两次密码必须一致2.表单由forms组件渲染
3.显示错误信息
进阶功能
使用ajax+forms组件完成注册功能
ajax接收error信息,修改dom,来显示错误信息!
答案
使用form表单实现
作业提到的3点要求,在将全局钩子的时候,已经演示出来了。
那么只要合格之后,在视图函数中插入一条记录到用户表中,就可以实现功能了!
下面介绍在上面演示的项目基础上,实现这些功能
修改models.py,增加一个用户表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class User(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) last_time = models.DateTimeField()
修改settings.py,注册app。最后一行添加应用名
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ]
使用下面2个命令生成表
python manage.py makemigrations
python manage.py migrate
手动增加一条记录
修改form.py,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django import forms # 必须导入模块 from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationError from app01.models import User # 导入user表class UserForm(forms.Form): # 必须继承Form
# 定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class": "form-control"})
# 定义字典,错误信息显示中文
# 限制数据为字符串,最小长度4,最大长度12
error_hints = {"required": "该字段不能为空", "invalid": "格式错误!"}
name = forms.CharField(max_length=12, label="姓名", widget=wid, error_messages=error_hints)
# 密码字段
pwd = forms.CharField(label="密码", widget=widgets.PasswordInput(attrs={"class": "form-control"}),
error_messages=error_hints)r_pwd </span>= forms.CharField(label=<span style="color: #800000;">"</span><span style="color: #800000;">确认密码</span><span style="color: #800000;">"</span>, widget=widgets.PasswordInput(attrs={<span style="color: #800000;">"</span><span style="color: #800000;">class</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">form-control</span><span style="color: #800000;">"</span><span style="color: #000000;">}), error_messages</span>=<span style="color: #000000;">error_hints) </span><span style="color: #0000ff;">def</span> clean_name(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 校验name值</span> val = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">name</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 获取输入的用户名</span> <span style="color: #0000ff;">if</span> len(val) >= 4: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断用户名长度</span> <span style="color: #0000ff;">if</span> val.isdigit() <span style="color: #0000ff;">is</span> False: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断用户名不是纯数字</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> User.objects.filter(name=val).exists(): <span style="color: #008000;">#</span><span style="color: #008000;"> 判断用户名是否存在</span> <span style="color: #0000ff;">return</span> val <span style="color: #008000;">#</span><span style="color: #008000;"> 返回正确的值</span> <span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名已存在</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名不能为纯数字</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">用户名长度不能小于4位</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> clean_pwd(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 校验pwd值</span> val = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">pwd</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 获取输入的密码</span> <span style="color: #0000ff;">if</span> len(val) >= 6: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断密码长度</span> <span style="color: #0000ff;">if</span> val.isdigit() <span style="color: #0000ff;">is</span> False: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断密码不是纯数字</span> <span style="color: #0000ff;">return</span> val <span style="color: #008000;">#</span><span style="color: #008000;"> 返回正确的值</span> <span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">密码不能为纯数字</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">密码长度不能小于6位</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> clean(self): <span style="color: #008000;">#</span><span style="color: #008000;"> 全局钩子</span> pwd = self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) r_pwd </span>= self.cleaned_data.get(<span style="color: #800000;">"</span><span style="color: #800000;">r_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> pwd <span style="color: #0000ff;">and</span> r_pwd <span style="color: #0000ff;">and</span> pwd != r_pwd: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断2次密码不为空,并且2次密码不相等</span> <span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">两次密码不一致</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span> self.cleaned_data <span style="color: #008000;">#</span><span style="color: #008000;"> 这句是固定写法,不能变动</span></pre>
修改views.py,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render, HttpResponse,redirect from app01.form import UserForm # 导入UserForm类 from app01.models import User import datetime# Create your views here.
def index(request):
return render(request, "index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)
print(type(form.errors)) # 打印
name = request.POST.get("name")
pwd = request.POST.get("pwd")
last_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
ret = User.objects.create(name=name,pwd=pwd,last_time=last_time)
if ret:
# return HttpResponse("添加成功")
return redirect('/index/')</span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">###fail###</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #008000;">#</span><span style="color: #008000;"> print(form.cleaned_data)</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(form.errors) </span><span style="color: #008000;">#</span><span style="color: #008000;"> # 获取email错误信息,返回一个错误列表,可以切片</span> <span style="color: #008000;">#</span><span style="color: #008000;"> print(form.errors.get("email"))</span> <span style="color: #008000;">#</span><span style="color: #008000;"> # 获取第一个错误信息</span> <span style="color: #008000;">#</span><span style="color: #008000;"> print(form.errors.get("email")[0])</span> g_error = form.errors.get(<span style="color: #800000;">"</span><span style="color: #800000;">__all__</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 接收全局钩子错误信息</span> <span style="color: #0000ff;">if</span> g_error: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断有错误信息的情况下</span> g_error = g_error[0] <span style="color: #008000;">#</span><span style="color: #008000;"> 取第一个错误信息</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 将form和g_error变量传给adduser.html</span> <span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>, {<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>: form, <span style="color: #800000;">"</span><span style="color: #800000;">g_error</span><span style="color: #800000;">"</span><span style="color: #000000;">: g_error}) </span><span style="color: #0000ff;">else</span>: <span style="color: #008000;">#</span><span style="color: #008000;"> 默认是get请求(地址栏输入访问时)</span> form = UserForm() <span style="color: #008000;">#</span><span style="color: #008000;"> 没有表单数据的form</span> <span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span>: form})</pre>
修改adduser.html,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <style> .error { color: red; } </style> </head> <body><div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }} <span class="error pull-right">{{ field.errors.0 }}</span>
{% if field.label == "确认密码" %}
<span class="error pull-right">{{ g_error|default_if_none:"" }}</span>
{% endif %}
</div>
{% endfor %}
<br/>
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div></body>
</html>
访问页面添加用户界面
查看用户表记录,发现多了一条
ajax+forms组件实现
在上面的代码上,增加ajax功能
修改urls.py,增加路径add_ajajx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('adduser/', views.adduser), path('add_ajax/', views.add_ajax), ]
修改views.py,增加视图函数add_ajajx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render, HttpResponse,redirect from app01.form import UserForm # 导入UserForm类 from app01.models import User import datetime import json# Create your views here.
def index(request):
return render(request, "index.html")def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
else: # 默认是get请求(地址栏输入访问时)
form = UserForm() # 没有表单数据的form<span style="color: #0000ff;">return</span> render(request, <span style="color: #800000;">"</span><span style="color: #800000;">adduser.html</span><span style="color: #800000;">"</span>,{<span style="color: #800000;">"</span><span style="color: #800000;">form</span><span style="color: #800000;">"</span><span style="color: #000000;">: form})
def add_ajax(request):
if request.method == "POST": # 判断POST请求
print(request.POST)
form = UserForm(request.POST) #
result = {"state": False,"name":"","pwd":"","r_pwd":""}
if form.is_valid():
name = request.POST.get("name")
pwd = request.POST.get("pwd")
last_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
ret = User.objects.create(name=name, pwd=pwd, last_time=last_time)
if ret:
result["state"] = True
return HttpResponse(json.dumps(result,ensure_ascii=False))
else:
print(form.errors)
if form.errors: # 判断有错误信息的情况下
if form.errors.get("name"):
result["name"] = form.errors.get("name")[0]
if form.errors.get("pwd"):
result["pwd"] = form.errors.get("pwd")[0]
if form.errors.get("r_pwd"):
result["r_pwd"] = form.errors.get("r_pwd")[0]g_error </span>= form.errors.get(<span style="color: #800000;">"</span><span style="color: #800000;">__all__</span><span style="color: #800000;">"</span>) <span style="color: #008000;">#</span><span style="color: #008000;"> 接收全局钩子错误信息</span> <span style="color: #0000ff;">if</span> g_error: <span style="color: #008000;">#</span><span style="color: #008000;"> 判断有错误信息的情况下</span> g_error = g_error[0] <span style="color: #008000;">#</span><span style="color: #008000;"> 取第一个错误信息</span> result[<span style="color: #800000;">"</span><span style="color: #800000;">r_pwd</span><span style="color: #800000;">"</span>] =<span style="color: #000000;"> g_error </span><span style="color: #0000ff;">return</span> HttpResponse(json.dumps(result,ensure_ascii=False))</pre>
修改adduser.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <style> .error { color: red; }.col</span>-center-<span style="color: #000000;">block { position: absolute; top: </span>50%<span style="color: #000000;">; left: </span>18%<span style="color: #000000;">; </span>-webkit-transform: translateY(-50%<span style="color: #000000;">); </span>-moz-transform: translateY(-50%<span style="color: #000000;">); </span>-ms-transform: translateY(-50%<span style="color: #000000;">); </span>-o-transform: translateY(-50%<span style="color: #000000;">); transform: translateY(</span>-50%<span style="color: #000000;">); } </span></style>
</head>
<body>
{% csrf_token %}
<div class="container col-center-block">
<div class="row ">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }} <span class="error pull-right">{{ field.errors.0 }}</span>
{% if field.label == "确认密码" %}
<span class="error pull-right">{{ g_error|default_if_none:"" }}</span>
{% endif %}
</div>
{% endfor %}
<br/>
<input type="button" class="btn btn-success btn-sm" id="sub" value="注册">
</form>
</div>
</div>
</div>
<script src="/static/js/jquery.min.js"></script>
{#sweetalert插件#}
<script src="http://mishengqiang.com/sweetalert/js/sweetalert-dev.js"></script>
<link rel="stylesheet" href="http://mishengqiang.com/sweetalert/css/sweetalert.css">
<script>
$(function () {
$("#id_name").blur(function () {
var csrf = $("[name=csrfmiddlewaretoken]").val(); //csrf
var name = $("#id_name").val(); //用户名
if (name.length != 0) {
$.ajax({
url: "/zhuce_ajax/",
type: "post",
data: {
'name': name,
csrfmiddlewaretoken: csrf,
},
success: function (data) {
var data = JSON.parse(data); //反序列化数据
console.log(data);
if (data.name) { //判断用户是否有错误信息
$("#id_name").next().text(data.name) //修改span标签的文本
} else {
$("#id_name").next().text("") //验证通过后,清空文件
}
}}); } }); $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">).blur(function () { var csrf </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">[name=csrfmiddlewaretoken]</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">csrf var pwd </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">密码 </span><span style="color: #0000ff;">if</span> (pwd.length !=<span style="color: #000000;"> 0) { $.ajax({ url: </span><span style="color: #800000;">"</span><span style="color: #800000;">/zhuce_ajax/</span><span style="color: #800000;">"</span><span style="color: #000000;">, type: </span><span style="color: #800000;">"</span><span style="color: #800000;">post</span><span style="color: #800000;">"</span><span style="color: #000000;">, data: { </span><span style="color: #800000;">'</span><span style="color: #800000;">name</span><span style="color: #800000;">'</span><span style="color: #000000;">: name, </span><span style="color: #800000;">'</span><span style="color: #800000;">pwd</span><span style="color: #800000;">'</span><span style="color: #000000;">: pwd, csrfmiddlewaretoken: csrf, }, success: function (data) { var data </span>= JSON.parse(data); //<span style="color: #000000;">反序列化数据 console.log(data); </span><span style="color: #0000ff;">if</span> (data.pwd) { //<span style="color: #000000;">判断密码是否有错误信息 $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span>).next().text(data.pwd) //<span style="color: #000000;">修改span标签的文本 } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span>).next().text(<span style="color: #800000;">""</span>) //<span style="color: #000000;">验证通过后,清空文件 } } }); } }); $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_r_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">).blur(function () { var csrf </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">[name=csrfmiddlewaretoken]</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">csrf var pwd </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">密码 var r_pwd </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">#id_r_pwd</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">确认密码 </span><span style="color: #0000ff;">if</span> (r_pwd.length !=<span style="color: #000000;"> 0) { $.ajax({ url: </span><span style="color: #800000;">"</span><span style="color: #800000;">/zhuce_ajax/</span><span style="color: #800000;">"</span><span style="color: #000000;">, type: </span><span style="color: #800000;">"</span><span style="color: #800000;">post</span><span style="color: #800000;">"</span><span style="color: #000000;">, data: { </span><span style="color: #800000;">'</span><span style="color: #800000;">name</span><span style="color: #800000;">'</span><span style="color: #000000;">: name, </span><span style="color: #800000;">'</span><span style="color: #800000;">pwd</span><span style="color: #800000;">'</span><span style="color: #000000;">: pwd, </span><span style="color: #800000;">'</span><span style="color: #800000;">r_pwd</span><span style="color: #800000;">'</span><span style="color: #000000;">: r_pwd, csrfmiddlewaretoken: csrf, }, success: function (data) { var data </span>= JSON.parse(data); //<span style="color: #000000;">反序列化数据 console.log(data); </span><span style="color: #0000ff;">if</span> (data.r_pwd) { //<span style="color: #000000;">判断确认密码是否有错误信息 $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_r_pwd</span><span style="color: #800000;">"</span>).next().text(data.r_pwd) //<span style="color: #000000;">修改span标签的文本 } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_r_pwd</span><span style="color: #800000;">"</span>).next().text(<span style="color: #800000;">""</span>) //<span style="color: #000000;">验证通过后,清空文件 } } }); } }); $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#sub</span><span style="color: #800000;">"</span><span style="color: #000000;">).click(function () { var csrf </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">[name=csrfmiddlewaretoken]</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">csrf var name </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">#id_name</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">用户名 var pwd </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">密码 var r_pwd </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">#id_r_pwd</span><span style="color: #800000;">"</span>).val(); //<span style="color: #000000;">确认密码 $.ajax({ url: </span><span style="color: #800000;">"</span><span style="color: #800000;">/zhuce_ajax/</span><span style="color: #800000;">"</span>, //<span style="color: #000000;">请求的url type: </span><span style="color: #800000;">"</span><span style="color: #800000;">post</span><span style="color: #800000;">"</span>, //<span style="color: #000000;">默认get data: { name: name, pwd: pwd, r_pwd: r_pwd, csrfmiddlewaretoken: csrf }, success: function (data) { </span>//<span style="color: #000000;">data接收响应体,必须要有 var data </span>= JSON.parse(data); //<span style="color: #000000;">反序列化数据 {</span><span style="color: #008000;">#</span><span style="color: #008000;">console.log(data.state);#}</span> {<span style="color: #008000;">#</span><span style="color: #008000;">console.log(data); //打印响应体#}</span> <span style="color: #0000ff;">if</span><span style="color: #000000;"> (data.state) { console.log(</span><span style="color: #800000;">"</span><span style="color: #800000;">注册成功</span><span style="color: #800000;">"</span><span style="color: #000000;">); swal({ title: </span><span style="color: #800000;">'</span><span style="color: #800000;">注册成功</span><span style="color: #800000;">'</span><span style="color: #000000;">, type: </span><span style="color: #800000;">'</span><span style="color: #800000;">success</span><span style="color: #800000;">'</span>, //<span style="color: #000000;">展示成功的图片 timer: </span>500, //<span style="color: #000000;">延时500毫秒 showConfirmButton: false </span>//<span style="color: #000000;">关闭确认框 }, function () { window.location.href </span>= <span style="color: #800000;">"</span><span style="color: #800000;">/index/</span><span style="color: #800000;">"</span>; //<span style="color: #000000;">跳转首页 }); } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { console.log(</span><span style="color: #800000;">"</span><span style="color: #800000;">注册失败</span><span style="color: #800000;">"</span><span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (data.name) { //<span style="color: #000000;">判断用户是否有错误信息 $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_name</span><span style="color: #800000;">"</span>).next().text(data.name) //<span style="color: #000000;">修改span标签的文本 } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_name</span><span style="color: #800000;">"</span>).next().text(<span style="color: #800000;">""</span>) //<span style="color: #000000;">验证通过后,清空文件 } </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (data.pwd) { $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">).next().text(data.pwd) } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_pwd</span><span style="color: #800000;">"</span>).next().text(<span style="color: #800000;">""</span><span style="color: #000000;">) } </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (data.r_pwd) { $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_r_pwd</span><span style="color: #800000;">"</span><span style="color: #000000;">).next().text(data.r_pwd) } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#id_r_pwd</span><span style="color: #800000;">"</span>).next().text(<span style="color: #800000;">""</span><span style="color: #000000;">) } } } }) }) })
</script>
</body>
</html>
访问页面:
测试效果如下:
查看用户表,发现多了一条记录
完整代码,请参考github
https://github.com/py3study/bms_multi
参考资料:
转载声明:
作者:肖祥
出处: https://www.cnblogs.com/xiao987334176/