django forms的常用命令及方法(三)

由于本人整理需要,抄至:https://www.cnblogs.com/haowen980/p/9277257.html (源文)

校验字段功能

之前写的视图函数,提交的数据,没有做校验,就调教到数据库里面了。这样是不对的。

比如:用户名,必须要符合一定的长度。密码复杂度,等等。

forms组件最大的作用,就是做数据校验。

 

普通做法,一个一个写校验规则,没有解耦。校验规则,都在视图函数里面。

新建项目formDemo

新建urls.py ,新增路径index

1 from app01 import views
2 urlpatterns = [
3     path('admin/', admin.site.urls),
4     path('index/', views.index),
5 ]

修改views.py ,新增index视图函数,form组件先放到视图函数

单独起一个类,后续会分离出来

 1 from django.shortcuts import render
 2  
 3 # Create your views here.
 4 from django import forms  # 必须导入模块
 5 class DemoForm(forms.Form):  # 必须继承Form
 6     #限制数据为字符串,最大长度32
 7     name = forms.CharField(max_length=32)
 8     age = forms.IntegerField()  # 限制为数字
 9     email = forms.EmailField()  # 限制为邮箱格式
10  
11 def index(request):
12     return render(request,"index.html")

 templates新增index.html,里面是空的

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8  
 9 </body>
10 </html>

打开Pycharm,点击左下角的Django Console

 

输入以下命令,导入视图函数的DemoForm类

1 from app01.views import DemoForm

 效果如下:

DemoForm类是用来做校验的,它接收一个字典。字典必须包含2个key,分别是name,age,email

测试一个字典数据

执行下面2个命令

1 form=DemoForm({"name":"john","age":"21","email":"123@163.com"})
2 form.is_valid()

效果如下:输出True

解释:

is_valid()表示执行校验,如果3个key都符合要求,输出True

测试1:age不符合

3个必须同时成立才行

在DemoForm里面,等式左边对应的是key,等式右边对应校验规则

它有一个默认规则,不能为空

 

测试2:少一个字段

从结果上来看,也是可以通过的。

它只校验指定的字段,那么额外的键值,会忽略

 

网页校验

修改urls.py,增加路径addbook

1 from app01 import views
2 urlpatterns = [
3     path('admin/', admin.site.urls),
4     path('index/', views.index),
5     path('addbook/', views.addbook),
6 ]

修改views.py,增加addbook视图函数,完整代码如下:

 1 from django.shortcuts import render,HttpResponse
 2  
 3 # Create your views here.
 4 from django import forms
 5 class DemoForm(forms.Form):
 6     name = forms.CharField(max_length=32)
 7     age = forms.IntegerField()
 8     email = forms.EmailField()
 9 class UserForm(forms.Form):
10     #限制数据为字符串,最小长度4,最大长度12
11     name = forms.CharField(min_length=4,max_length=12)
12     age = forms.IntegerField()  #限制为数字
13     #限制长度为11位
14     tel = forms.CharField(min_length=11,max_length=11)
15  
16  
17 def index(request):
18  
19     return render(request,"index.html")
20  
21 def addbook(request):
22     if request.method == "POST":
23         #将post数据传给UserForm
24         form = UserForm(request.POST)
25         if forms.is_valid():    #验证数据
26             print("success")
27         else:
28             print("fail")
29         return HttpResponse("ok")
30      
31     return render(request,"addbook.html")

templates新增addbook.html

做表单校验的时候,一定要注意,表单的name和class的属性必须一一对应

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <h3>添加用户</h3>
 9 <form action="" method="post">
10     {% csrf_token %}
11     <lable>姓名</lable><input type="text" name="name"/><br/>
12     <lable>年龄</lable><input type="text" name="age"/><br/>
13     <lable>邮箱</lable><input type="text" name="email"/><br/>
14     <lable>手机号码</lable><input type="text" name="tel"/>
15     <br/>
16     <input type="submit">
17 </form>
18 </body>
19 </html>

 网页访问添加页面,输出信息

提交之后

控制台输出:

 

 

空表单直接提交

Pycharm控制台输出:fail

 

is_valid()

form.is_valid() 它做了2件事情:

1.将数据传给form

2.将验证数据拆分到2个容器中

self.cleandtate={}表示干净的数据

self.error = {}表示验证不通过的数据

self表示UserForm类的实例对象


addbook视图函数

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))

        return HttpResponse("ok")

    return render(request,"addbook.html")

 再次提交数据

 

 Pycharm控制台输出:

 

虽然POST发送了5个键值,但是UserForm只校验3个键值。

form.cleaned_data 输出了3个键值

form.errors 输出的内容空,它的类型为ErrorDict

只要有一个错误,就会走else 

  

 

错误数据演示

修改views.py,修改UserForm,增加邮箱

复制代码
class UserForm(forms.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控制台输出:

form.errors输出了一段Html标签,提示邮箱格式错误

提取email错误信息

修改UserForm

 1 def addbook(request):
 2     if request.method == "POST":
 3         # 将post数据传给UserForm
 4         form = UserForm(request.POST)
 5         print(request.POST)
 6         if form.is_valid():  # 验证数据
 7             print("###success###")
 8             print(form.cleaned_data)  # 所有干净的字段以及对应的值
 9             # ErrorDict : {"校验错误的字段":["错误信息",]}
10             print(form.errors)
11             print(type(form.errors))  # 打印
12         else:
13             print("###fail###")
14             print(form.cleaned_data)
15             print(form.errors)
16             # 获取email错误信息,返回一个错误列表,可以切片
17             print(form.errors.get("email"))
18             # 获取第一个错误信息
19             print(form.errors.get("email")[0])
20  
21         return HttpResponse("ok")
22  
23     return render(request,"addbook.html")

 pycharm控制台输出

form.errors.get("email") 可以提取email的错误信息,它返回的是一个错误列表

通过切片,可以获取第一个错误信息

渲染标签功能

渲染方式1

使用自带的模板属性渲染

上面讲的form表单里面的元素,是手动写的。form组件可以帮你实现渲染表单元素!

那么需要渲染哪些元素,取决于UserForm这个自定义类的属性来决定的

举例:

修改addbook视图函数

 1 def addbook(request):
 2     if request.method == "POST":
 3         # 将post数据传给UserForm
 4         form = UserForm(request.POST)
 5         print(request.POST)
 6         if form.is_valid():  # 验证数据
 7             print("###success###")
 8             print(form.cleaned_data)  # 所有干净的字段以及对应的值
 9             # ErrorDict : {"校验错误的字段":["错误信息",]}
10             print(form.errors)
11             print(type(form.errors))  # 打印
12         else:
13             print("###fail###")
14             print(form.cleaned_data)
15             print(form.errors)
16             # 获取email错误信息,返回一个错误列表,可以切片
17             print(form.errors.get("email"))
18             # 获取第一个错误信息
19             print(form.errors.get("email")[0])
20  
21         return render(request, "adduser.html", {"form":form})
22  
23     else:
24         form = UserForm()
25         return render(request,"addbook.html",{"form":form})

  修改addbook.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <h3>添加用户</h3>
 9 <form action="" method="post">
10     {% csrf_token %}
11     {{ form.as_p }}
12     <br/>
13     <input type="submit">
14 </form>
15 </body>
16 </html>

as_p是一个特殊的属性,常见的有:

  • {{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
  • {{ form.as_p }} 将它们渲染在<p> 标签中
  • {{ form.as_ul }} 将它们渲染在<li> 标签中

 访问页面,效果如下:

 

使用浏览器工具,查看html代码

它使用了P标签来包裹

 laber的for属性和input的id属性是对应的。id的名字和UserForm类定义的属性是类似的,加了id_前缀。

 lable的显示的文字和UserForm类定义的属性是一样的,首字母大写了!

 

input的name属性和UserForm类定义的属性是一样的

默认自带required属性,不允许内容为空。

minlength的属性来源于UserForm类的定义。

注意:form组件只能渲染表单里面的元素,比如input标签。除此之外,其他的需要手写!

它的样式,太丑了!

渲染方式2

使用自定义的标签来包裹form变量

举例:

更改addbook.html

 

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <h3>添加用户</h3>
 9 <form action="" method="post">
10     {% csrf_token %}
11     <div>
12         <p>姓名</p>
13         {{ form.name }}
14     </div>
15     <div>
16         <p>年龄</p>
17         {{ form.age }}
18     </div>
19     <div>
20         <p>邮箱</p>
21         {{ form.email }}
22     </div>
23     <div>
24         <p>手机号码</p>
25         {{ form.tel }}
26     </div>
27     <input type="submit">
28 </form>
29 </body>
30 </html>  

刷新页面效果如下:

 

渲染方式3

使用for循环渲染

修改addbook.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <h3>添加用户</h3>
 9 <form action="" method="post">
10     {% csrf_token %}
11     {% for field in form %}
12         <div>
13             <label for=""> {{ field.label }}</label>
14             {{ field }}
15         </div>
16     {% endfor %}
17     <input type="submit">
18 </form>
19 </body>
20 </html>

刷新网页,效果如下:

field.label 表示属性名

field 表示input输入框

显示中文

将label换成中文,需要增加label属性

修改views.py里面的UserForm类

复制代码
1 class UserForm(forms.Form):  # 必须继承Form
2     #限制数据为字符串,最小长度4,最大长度12
3     name = forms.CharField(min_length=4,max_length=12,label="姓名")
4     age = forms.IntegerField(label="年龄")  # 限制为数字
5     email = forms.EmailField(label="邮箱")  # 限制为邮箱格式
6     #限制长度为11位
7     tel = forms.CharField(min_length=11,max_length=11,label="手机号码")
复制代码

刷新网页,效果如下:

 美化input输入框

需要使用bootstrap

修改urls.py,修改路径、

1 urlpatterns = [
2     path('admin/', admin.site.urls),
3     path('index/', views.index),
4     path('adduser/', views.adduser),
5 ]

修改views.py,将addbook重名为adduser

 1 def adduser(request):
 2     if request.method == "POST":
 3         # 将post数据传给UserForm
 4         form = UserForm(request.POST)
 5         print(request.POST)
 6         if form.is_valid():  # 验证数据
 7             print("###success###")
 8             print(form.cleaned_data)  # 所有干净的字段以及对应的值
 9             # ErrorDict : {"校验错误的字段":["错误信息",]}
10             print(form.errors)
11             print(type(form.errors))  # 打印
12         else:
13             print("###fail###")
14             print(form.cleaned_data)
15             print(form.errors)
16             # 获取email错误信息,返回一个错误列表,可以切片
17             print(form.errors.get("email"))
18             # 获取第一个错误信息
19             print(form.errors.get("email")[0])
20  
21         return render(request, "adduser.html", {"form":form})
22  
23     else:
24         form = UserForm()
25         return render(request,"adduser.html",{"form":form})
View Code

将addbook.html,重命名为adduser.html

引入bootstrap,代码如下:

访问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,完整代码如下:

 1 from django.shortcuts import render,HttpResponse
 2 
 3 # Create your views here.
 4 from django import forms
 5 from django.forms import widgets
 6 # class DemoForm(forms.Form):
 7 #     name = forms.CharField(max_length=32)
 8 #     age = forms.IntegerField()
 9 #     email = forms.EmailField()
10 class UserForm(forms.Form):
11     #定义变量,专门给text类型的输入框加class
12     wid = widgets.TextInput(attrs={"class":"form-control"})
13     #限制数据为字符串,最小长度4,最大长度12
14     name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid)
15     age = forms.IntegerField(label="年龄",widget=wid)  #限制为数字
16     email = forms.EmailField(label="邮箱",widget=wid)  #限制为邮箱格式
17     #限制长度为11位
18     tel = forms.CharField(min_length=11,max_length=11,label="手机号",widget=wid)
19 
20 def index(request):
21 
22     return render(request,"index.html")
23 
24 def adduser(request):
25     if request.method == "POST":
26         print(request.POST)
27         # 将post数据传给UserForm
28         form = UserForm(request.POST)
29         if form.is_valid():  # 验证数据
30             print("###success###")
31             print(form.cleaned_data)
32             print(form.errors)
33         else:
34             print("###fail###")
35             print(form.cleaned_data)
36             print(form.errors)
37             print(type(form.errors))
38             # 获取email错误信息,返回一个错误列表,可以切片
39             print(form.errors.get("email"))
40             # 获取第一个错误信息
41             print(form.errors.get("email")[0])
42 
43         return render(request, "adduser.html",{"form":form})
44 
45     else:
46         form = UserForm()
47         return render(request, "adduser.html", {'form':form})
48 
49 views.py
View Code

直接提交空数据,页面有错误提示

注意:这个提示是bootstrap做的,不是form组件

虽然jquery可以直接对表单进行验证,判断为空,或者其他规则。但是客户端浏览器的js代码,是可以跳过验证的。直接提交数据给服务器,如果服务器没有做数据校验,那么将面临风险!

修改adduser.html,在form标签后面增加novalidate,表示关闭bootstrap表单验证

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
 7 </head>
 8 <body>
 9  
10 <div class="container">
11     <div class="row">
12         <div class="col-md-6 col-md-offset-2">
13         <h3>添加用户</h3><br/>
14             <form action="" method="post" novalidate>
15                 {% csrf_token %}
16                 {% for field in form %}
17                     <div class="form-group">
18                         <label for="">{{ field.label }}</label>
19                         {{ field }}
20                     </div>
21                 {% endfor %}
22                 <br/>
23                 <input type="submit" class="btn btn-success btn-sm">
24             </form>
25         </div>
26     </div>
27 </div>
28  
29 </body>
30 </html>

刷新页面,填3个值,最后一个故意不填写

 

 

发现刚刚增加的数据,没有了。这样用户体验不好!用户得小心翼翼的输入每一个数据!

查看Pycharm控制台输出:

###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变量是带有表单数据的!

 1 def adduser(request):
 2     if request.method == "POST":
 3         # 将post数据传给UserForm
 4         form = UserForm(request.POST)
 5         print(request.POST)
 6         if form.is_valid():  # 验证数据
 7             print("###success###")
 8             print(form.cleaned_data)  # 所有干净的字段以及对应的值
 9             # ErrorDict : {"校验错误的字段":["错误信息",]}
10             print(form.errors)
11             print(type(form.errors))  # 打印
12             return HttpResponse("添加成功")
13         else:
14             print("###fail###")
15             # print(form.cleaned_data)
16             print(form.errors)
17             # # 获取email错误信息,返回一个错误列表,可以切片
18             # print(form.errors.get("email"))
19             # # 获取第一个错误信息
20             # print(form.errors.get("email")[0])
21         return render(request, "adduser.html", {"form":form})
22  
23     else:  # 默认是get请求(地址栏输入访问时)
24         form = UserForm()  # 没有表单数据的form
25         return render(request,"adduser.html",{"form":form})

再次刷新页面,数据就回来了!

 

 

数据怎么就回来了呢?

因为既然是POST请求,而且携带了POST数据,必然执行了form.is_valid()

虽然没有验证通过,但是执行下面一句代码时

return render(request, "adduser.html", {"form":form})

此时的form是含有POST表单数据的,所以页面才会渲染出来!

注意:当input属性为password时,是不会渲染的!除此之外,其他的表单元素,是可以渲染的

 

提交一个正确的数据

 

提示添加成功

 

显示错误信息

约定俗成,使用span标签来显示错误信息

修改adduser.html,增加span标签

 

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6         <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
 7 </head>
 8 <body>
 9  
10 <div class="container">
11     <div class="row">
12         <div class="col-md-6 col-md-offset-2">
13             <h3>添加用户</h3>
14             <form action="" method="post" novalidate>
15                 {% csrf_token %}
16                 {% for field in form %}
17                     <div>
18                         <label for=""> {{ field.label }}</label>
19                         {{ field }}<label>{{ field.errors.0 }}</label>
20                     </div>
21                 {% endfor %}
22                 <input type="submit" class="btn btn-success btn-sm">
23             </form>
24         </div>
25     </div>
26 </div>
27 </body>
28 </html> 

解释:

field.errors 表示错误列表。因为是列表,会有很多错误信息

field.errors.0 表示接收第一个错误信息。一般取第一个即可!

那么问题来了,get请求时,比如地址栏访问页面,他是娶不到值得,那么span标签是空得,但是不影响页面展示

 

直接提交空数据,页面会有英文提示,它表示此字段不允许为空

显示黑色,不好看,加一个样式

修改adduser.html ,增加样式,pull-right表示右对齐

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6         <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
 7 </head>
 8 <body>
 9  
10 <div class="container">
11     <div class="row">
12         <div class="col-md-6 col-md-offset-2">
13             <h3>添加用户</h3>
14             <form action="" method="post" novalidate>
15                 {% csrf_token %}
16                 {% for field in form %}
17                     <div class="form-group">
18                         <label for=""> {{ field.label }}</label>
19                         {{ field }}<span class="error pull-right">{{ field.errors.0 }}</span>
20                     </div>
21                 {% endfor %}
22                 <input type="submit" class="btn btn-success btn-sm">
23             </form>
24         </div>
25     </div>
26 </div>
27 </body>
28 </html>

刷新页面,效果如下:

错误信息显示中文

 显示中文需要在UserForm类中的字段增加error_message属性

 1 class UserForm(forms.Form): #必须继承Form
 2     #定义变量,专门text类型的输入框添加class
 3     wid = widgets.TextInput(attrs={"class":"form-control"})
 4     #定义字典,错误信息显示中文
 5     #限制数据为字符串,最小长度4,最大长度12
 6     error_hints = {"required":"该字段不能为空"}
 7     name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid,error_messages=error_hints)
 8     #限制为数字
 9     age = forms.IntegerField(label="年龄",widget=wid,error_messages=error_hints)
10     #限制为邮箱格式
11     email = forms.EmailField(label="邮箱",widget=widgets.EmailInput(attrs={"class":"form-control"}),error_messages=error_hints)
12     #限制长度为11位
13     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

举例:

要求用户名不能是纯数字

1 def clean_name(self):
2     val = self.cleaned_data.get("name")      #获取输入的用户名
3      
4     if not val.isdigit():       #判断不是数字类型
5      
6             return     val
7     else8             raise   ValidationError("用户名不能是纯数字")

注意:

clean_name 这个名字是有含义的,不能随便定义。name表示UserForm类的属性。clean表示校验 val 表示用户输入的用户名

val.isdigit() 表示判断输入的是否为数字,必须return一个值

raise 表示主动报错,必须接ValidationError。

上面这些要求是源代码定义的,具体可以看源代码。

views.py,完整代码如下:

 

 1 class UserForm(forms.Form):
 2     #定义变量,专门给text类型的输入框添加class
 3     wid = widgets.TextInput(attrs={"class":"form-control"})
 4     #定义字典,错误信息显示中文
 5     #限制数据为字符串,最小长度4,最大长度12
 6     error_hints = {"required":"该字段不能为空","invalid":"格式错误!"}
 7     name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid,error_messages=error_hints)
 8     #限制数字
 9     age = forms.IntegerField(label="年龄",widget=wid,error_messages=error_hints)
10     #限制为邮箱格式
11     email = forms.EmailField(label="邮箱",widget=widgets.EmailInput(attrs={"class":"form-control"}),error_messages=error_hints)
12     #限制长度为11位
13     tel = forms.CharField(min_length=11,max_length=11,label="手机号码",widget=wid,error_messages=error_hints)
14  
15     def clean_name(self):
16         val = self.cleaned_data.get("name")  # 获取输入的用户名
17  
18         if not val.isdigit():  # 判断不是数字类型
19             return val
20         else:
21             raise ValidationError("用户名不能是纯数字")

手机号码必须11位

修改UserForm类,增加clean_tel方法,完整代码如下:

手机号码必须11位

修改UserForm类,增加clean_tel方法,完整代码如下:

 1 class UserForm(forms.Form):
 2     #定义变量,专门给text类型的输入框添加class
 3     wid = widgets.TextInput(attrs={"class":"form-control"})
 4     #定义字典,错误信息显示中文
 5     #限制数据为字符串,最小长度4,最大长度12
 6     error_hints = {"required":"该字段不能为空","invalid":"格式错误!"}
 7     name = forms.CharField(min_length=4,max_length=12,label="姓名",widget=wid,error_messages=error_hints)
 8     #限制数字
 9     age = forms.IntegerField(label="年龄",widget=wid,error_messages=error_hints)
10     #限制为邮箱格式
11     email = forms.EmailField(label="邮箱",widget=widgets.EmailInput(attrs={"class":"form-control"}),error_messages=error_hints)
12     #限制长度为11位
13     tel = forms.CharField(max_length=11,label="手机号码",widget=wid,error_messages=error_hints)
14  
15     def clean_name(self):
16         val = self.cleaned_data.get("name")  # 获取输入的用户名
17  
18         if not val.isdigit():  # 判断不是数字类型
19             return val
20         else:
21             raise ValidationError("用户名不能是纯数字")
22  
23     def clean_tel(self):
24         val = self.cleaned_data.get("tel")
25         if len(val) == 11:  # 判断长度
26             return val
27         else:
28             raise ValidationError("手机号码必须11位")

注意:要去除tel里面的min_length,这是不严谨的写法!

 

重新访问页面,测试一下

年龄必须18岁以上

增加clean_age方法

1 def clean_age(self):
2         val = self.cleaned_data.get("age")
3         if int(val) > 18:  # input输入的值为字符串,必须转换为int
4             return val
5         else:
6             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原代码如下:

 1 def _clean_fields(self):
 2        for name, field in self.fields.items():
 3            # value_from_datadict() gets the data from the data dictionaries.
 4            # Each widget type knows how to retrieve its own data, because some
 5            # widgets split data over several HTML fields.
 6            if field.disabled:
 7                value = self.get_initial_for_field(field, name)
 8            else:
 9                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
10            try:
11                if isinstance(field, FileField):
12                    initial = self.get_initial_for_field(field, name)
13                    value = field.clean(value, initial)
14                else:
15                    value = field.clean(value)
16                self.cleaned_data[name] = value
17                if hasattr(self, 'clean_%s' % name):
18                    value = getattr(self, 'clean_%s' % name)()
19                    self.cleaned_data[name] = value
20            except ValidationError as e:
21                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是是一个规则对象.

下面是一个完整例子:

 1 在views.py中
 2 
 3 from django.shortcuts import render,HttpResponse,redirect
 4 from django.views import View
 5 from .models import Fruit,Buyer
 6 from django import forms
 7 class buyerform(forms.Form):
 8     error_hints= {"required":"该字段不能为空","invalid":"格式错误!"}
 9     name=forms.CharField(max_length=12,label="名字",error_messages=error_hints)
10     age=forms.IntegerField(label="年龄",error_messages=error_hints)
11     email=forms.EmailField(max_length=32,label="邮箱",error_messages={"required":"该字段不能为空","invalid":"格式错误!"})
12     tel=forms.CharField(min_length=11,max_length=11,label="电话",error_messages=error_hints)
13     password=forms.CharField(label="密码",error_messages=error_hints,widget=forms.PasswordInput)
14     def clean_password(self):
15         val=self.cleaned_data.get('password')
16         if len(val)>5:
17             return val
18         else:
19             raise forms.ValidationError("密码必须5位或5位以上")
20 
21 
22 class index(View):
23     def get(self,request):
24         form = buyerform()
25         return render(request,'adduser.html',{'form':form})
26 
27     def post(self,request):
28         form=buyerform(request.POST)
29         if form.is_valid():
30             print "sucess"
31             print form.cleaned_data
32             print form.errors
33             return HttpResponse('OK')
34         else:
35             print "fail"
36             print form.cleaned_data
37             print form.errors
38             print form.errors.get('age')
39             print type(form.errors.get('age'))
40         return render(request,'adduser.html',{'form':form})
 1 在html中
 2 <!DOCTYPE html>
 3 <html lang="en">
 4 <head>
 5     <meta charset="UTF-8">
 6     <title>Title</title>
 7 {#    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">#}
 8 </head>
 9 <body>
10 <div class="container">
11     <div class="row">
12         <div class="col-md-6 col-md-offset-2">
13         <h3>添加用户</h3><br/>
14             <form action="" method="post" novalidate>
15                 {% csrf_token %}
16                 {% for field in form %}
17                     <div class="form-group">
18                         <label for="">{{ field.label }}</label>
19                         {{ field }}<span class="error pull-right">{{ field.errors.0 }}</span>
20                     </div>
21                 {% endfor %}
22                 <br/>
23                 <input type="submit" class="btn btn-success btn-sm">
24             </form>
25         </div>
26     </div>
27 </div>
28 </body>
29 </html>

 

posted @ 2019-07-07 21:52  代码家园  阅读(552)  评论(0)    收藏  举报