Day22-Django之Form组件验证
1. Django里面的Form专门用来做验证。
用Form创建一个类,把用户发来的数据放到request.POST里面发给这个类,这个类会帮忙做验证。
返回3个结果:是否验证成功了,所有的正确信息,所有的错误信息。
name值必须与FM类里面的对应才能拿到数据。
2. 定义了一个类,它继承了forms.Form。我想验证哪个,就把哪个写到这个类里。
from django import forms class FM(forms.Form): user=forms.CharField() pwd=forms.CharField() email=forms.EmailField()
3.views.py,
r1=obj.is_valid()就是做验证,如果验证通过,则返回True; 如果验证失败,则返回False.
#####################From######################## from django import forms class FM(forms.Form): user=forms.CharField() pwd=forms.CharField() email=forms.EmailField() def fm(request): if request.method=='GET': return render(request,'fm.html') elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) #创建对象,把request.POST里面的数据都传过去。 r1=obj.is_valid() print(r1) return redirect('/fm/')
4. 完善程序:通过obj.is_valid,obj.cleaned_data, obj.errors 三种方法得到了所有验证结果。
views.py
#####################From######################## from django import forms class FM(forms.Form): user=forms.CharField() pwd=forms.CharField() email=forms.EmailField() def fm(request): if request.method=='GET': return render(request,'fm.html') elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: print(obj.cleaned_data) #输出所有的正确信息 else: print(obj.errors.as_json()) #输出所有的错误信息。本来是字符串,通过as_json()方法可以得到字典类型的输出。 return redirect('/fm/')
5. 通过传参数,也可以定制想要显示的错误信息。把错误信息显示为中文。把code下所对应的值替换掉。
required 替换为:不能为空。
invalid 替换为 格式错误。
#####################From######################## from django import forms class FM(forms.Form): user=forms.CharField(error_messages={'required':'用户名不能为空'}) pwd=forms.CharField() email=forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) def fm(request): if request.method=='GET': return render(request,'fm.html') elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: print(obj.cleaned_data) else: print(obj.errors) return redirect('/fm/')
6. 完善密码部分的验证:最大长度-最小长度
views.py
#####################From######################## from django import forms class FM(forms.Form): user=forms.CharField(error_messages={'required':'用户名不能为空'}) pwd=forms.CharField( max_length=12, min_length=6, error_messages={'required': '密码不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'} ) email=forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) def fm(request): if request.method=='GET': return render(request,'fm.html') elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: print(obj.cleaned_data) else: print(obj.errors) return redirect('/fm/')
效果:
7. 把错误信息obj.errors传到前端,
views.py
#####################From######################## from django import forms class FM(forms.Form): user=forms.CharField(error_messages={'required':'用户名不能为空'}) pwd=forms.CharField( max_length=12, min_length=6, error_messages={'required': '密码不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'} ) email=forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) def fm(request): if request.method=='GET': return render(request,'fm.html') elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: print(obj.cleaned_data) else: #ErrorDict, obj.errors继承了Dict,所以取数据的时候不能通过点,应该通过['user'] print(obj.errors['user']) return render(request,'fm.html',{'obj':obj})
obj.errors 里面包含了所有的错误信息。 {{obj.errors.user.0}} 取user下面的第一个错误信息。
fm.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/fm/" method="POST"> {% csrf_token %} <p><input type="text" name="user" placeholder="username"/>{{obj.errors.user.0}}</p> <p><input type="password" name="pwd" placeholder="password"/>{{obj.errors.pwd.0}}</p> <p><input type="text" name="email" placeholder="email"/>{{obj.errors.email.0}}</p> <input type="submit" value="提交"/> </form> </body> </html>
效果:
8. 到目前为止,一点提交,错误信息是显示出来了,可是用户输入的值也被刷新,找不到了。
obj可以自动帮我们生成各种标签。
views.py
#####################From######################## from django import forms class FM(forms.Form): user=forms.CharField(error_messages={'required':'用户名不能为空'}) pwd=forms.CharField( max_length=12, min_length=6, error_messages={'required': '密码不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'} ) email=forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) def fm(request): if request.method=='GET': obj=FM() #当用GET方式请求时,也需要创建一个对象。不需要传参数,因为在前端不需要看到任何数据。 return render(request,'fm.html',{'obj':obj}) elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: print(obj.cleaned_data) else: #ErrorDict继承了Dict #print(obj.errors['user']) return render(request,'fm.html',{'obj':obj})
fm.html: <p>{{obj.user}}{{obj.errors.user.0}}</p> ,写obj.user, 自动生成input标签,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/fm/" method="POST"> {% csrf_token %} <p>{{obj.user}}{{obj.errors.user.0}}</p> <p>{{obj.pwd}}{{obj.errors.pwd.0}}</p> <p>{{obj.email}}{{obj.errors.email.0}}</p> <input type="submit" value="提交"/> </form> </body> </html>
效果:自动生成了input标签。高级浏览器生成的标签比较多,比较全。
而且如果输入不合法的话,显示错误信息的同时,也会保留用户当前的输入。
obj.cleaned_data 里面存放的是所有正确的值,通过验证的值。是一个字典,所以可以通过
models.UserInfo.objects.create(**obj.cleaned_data) 生成表中数据。
通过form做了2件事,
1-做用户请求的验证;2-帮用户在页面上生成HTML标签;生成HTML标签的同时,替用户保留了上次提交的数据。
9.还有更简单的方法,
fm.html修改如下: obj.as_p 意思是p标签。
fm.html修改如下: obj.as_ur 意思是ur标签
fm.html修改如下: obj.as_table 意思是table标签 ; 注意用table的时候,要在外面加1个table标签。
上述3种,生成方便,但是定制性差。所以还是建议用下面的
程序粘贴:
models.py
from django.db import models # Create your models here. class UserInfo(models.Model): user=models.CharField(max_length=32)
fm.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/fm/" method="POST"> {% csrf_token %} <p>{{obj.user}}{{obj.errors.user.0}}</p> <p>{{obj.pwd}}{{obj.errors.pwd.0}}</p> <p>{{obj.email}}{{obj.errors.email.0}}</p> <input type="submit" value="提交"/> </form> </body> </html>
views.py
#####################From######################## from django import forms class FM(forms.Form): user=forms.CharField(error_messages={'required':'用户名不能为空'}) pwd=forms.CharField( max_length=12, min_length=6, error_messages={'required': '密码不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'} ) email=forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) from app01 import models def fm(request): if request.method=='GET': obj=FM() return render(request,'fm.html',{'obj':obj}) elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: models.UserInfo.objects.create(**obj.cleaned_data) else: #ErrorDict继承了Dict #print(obj.errors['user']) return render(request,'fm.html',{'obj':obj})
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/$', views.login), url(r'^index/$', views.index), url(r'^logout/$', views.logout), url(r'^test/(\d+)$', views.test), url(r'^cache/$', views.cache), url(r'^signal/$', views.signal), url(r'^fm/$', views.fm), ]
10. 那么input框的样式怎么设置呢?
CharField,emailField 这些是做验证功能的。CharField里面有个type=text的默认插件。
生成HTML的功能在另外一个插件中完成,widget就是插件的意思。
widget=widgets.Textarea(attrs={'class':'c1'}), widgets.Textarea:定制插件。 attrs:定义样式。
from django.forms import widgets
#####################From######################## from django import forms from django.forms import widgets class FM(forms.Form): #字段本身只做验证,CharField内部隐含了一个插件。 user=forms.CharField( error_messages={'required':'用户名不能为空'}, widget=widgets.Textarea() ) pwd=forms.CharField( max_length=12, min_length=6, error_messages={'required': '密码不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'} ) email=forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) from app01 import models def fm(request): if request.method=='GET': obj=FM() return render(request,'fm.html',{'obj':obj}) elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: models.UserInfo.objects.create(**obj.cleaned_data) else: #ErrorDict继承了Dict #print(obj.errors['user']) return render(request,'fm.html',{'obj':obj})
效果:
11. 给Textarea加上样式
#####################From######################## from django import forms from django.forms import widgets class FM(forms.Form): #字段本身只做验证,CharField内部隐含了一个插件。 user=forms.CharField( error_messages={'required':'用户名不能为空'}, widget=widgets.Textarea(attrs={'class':'c1'}) ) pwd=forms.CharField( max_length=12, min_length=6, error_messages={'required': '密码不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'} ) email=forms.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) from app01 import models def fm(request): if request.method=='GET': obj=FM() return render(request,'fm.html',{'obj':obj}) elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: models.UserInfo.objects.create(**obj.cleaned_data) else: #ErrorDict继承了Dict #print(obj.errors['user']) return render(request,'fm.html',{'obj':obj})
可以定义字段,定义在页面上显示的是什么插件,还可以自定义样式。
from django.forms import fields 所有字段都在这里面放着呢。
以后就不用写成forms.CharField的样子的,只需要写成fields.CharField的样子就可以了。
from django.forms import widgets 所有插件都在这里面放着呢。
widgets插件里面都有些什么呢:input,select,checkbox,radio等都有。
通过is_valid(),obj.cleaned_data(),obj.errors()拿到所有的返回值,在每个field字段里面做验证,字段里面包含了插件,
是专门用来生成HTML页面的
12,widget=widgets.PasswordInput(attrs={'class':'c2'}) 专门针对password的插件。attrs是定义样式。
效果:
13,其它字段的介绍,专门用来做验证的。
label标签和默认值示例
FileField(Field)示例:真正上传的时候,以前form表单里面需要加一句特殊的设置,否则上传不成功。
在此处上传的文件也保存在cleaned_data里面,cleaned_data里面保存的时候是字典的格式。在此处拿到文件名(key)以后,也需要执行chunks才能成功。
FilePathField(ChoiceField)示例:把一个文件夹下的所有文件都显示出来了。
ChoiceField(Field)示例:
city=fields.MultipleChoiceField
14. 创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;
14.1、Django内置字段如下:
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) #继承了Field,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:12
DurationField(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.ModelMultipleChoiceField
TypedChoiceField(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) 能实现1个字段对应多个input框
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类型
...
14.2 Django常用插件:
>>> import uuid # make a UUID based on the host ID and current time >>> uuid.uuid1() # doctest: +SKIP UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') # make a random UUID >>> uuid.uuid4() # doctest: +SKIP UUID('16fd2706-8baf-433b-82eb-8c7fada847da') # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') # make a UUID from a string of hex digits (braces and hyphens ignored) >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') # convert a UUID to a string of hex digits in standard form >>> str(x) '00010203-0405-0607-0809-0a0b0c0d0e0f' # get the raw 16 bytes of the UUID >>> x.bytes b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
常用选择插件
# 单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,值为字符串,写法1 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 单select,值为字符串,写法2 # 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 # )
笔记
15. 初始化操作
程序粘贴:
views.py
#####################From######################## from django import forms from django.forms import widgets from django.forms import fields #字段都在fields中 class FM(forms.Form): #字段本身只做验证,CharField内部隐含了一个插件。 user=fields.CharField( error_messages={'required':'用户名不能为空'}, widget=widgets.Textarea(attrs={'class':'c1'}), label="用户名", #initial='root', ) pwd=fields.CharField( max_length=12, min_length=6, error_messages={'required': '密码不能为空','min_length':'密码长度不能小于6','max_length':'密码长度不能大于12'}, widget=widgets.PasswordInput(attrs={'class':'c2'}) ) email=fields.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误'}) f=fields.FileField() #p=fields.FilePathField(path='app01') city1=fields.ChoiceField( choices=[(0,'上海'),(1,'广州'),(2,'东莞'),] ) city2=fields.MultipleChoiceField( choices=[(0,'上海'),(1,'广州'),(2,'东莞'),] ) from app01 import models def fm(request): if request.method=='GET': #从数据库中把数据都获取到 dic={ 'user':'user1', 'pwd':'123123', 'email':'sdfsd', 'city1':1, 'city2':[1,2] } obj=FM(initial=dic) return render(request,'fm.html',{'obj':obj}) elif request.method=='POST': #获取用户提交的所有数据,对每条数据进行验证,# # 成功之后,获取所有正确的信息;若失败,显示错误信息 obj=FM(request.POST) r1=obj.is_valid() if r1: models.UserInfo.objects.create(**obj.cleaned_data) else: #ErrorDict继承了Dict #print(obj.errors['user']) return render(request,'fm.html',{'obj':obj})
fm.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/fm/" method="POST"> {% csrf_token %} <p>{{obj.user.label}}{{obj.user}}{{obj.errors.user.0}}</p> <p>{{obj.pwd}}{{obj.errors.pwd.0}}</p> <p>{{obj.email}}{{obj.errors.email.0}}</p> <p>{{obj.f}}{{obj.errors.f.0}}</p> {{obj.p}} {{obj.city1}} {{obj.city2}} <input type="submit" value="提交"/> </form> </body> </html>
参考老师博客:http://www.cnblogs.com/wupeiqi/articles/6144178.html