Django之Form组件(***)
Django之Form组件
Form组件,用来做一些数据的提前验证,比如登录注册中,我们定义的是邮箱登录,但是用户却手机号登录,那么用Form组件去实现这个验证过程的话,数据的判断逻辑就不会去数据库匹配啦,这样反而会减轻数据库的压力。
所以,Form组件的功能是对用户的请求数据库做验证的。并且对获取的数据也可以做验证功能。
以往的登录注册中的问题:
在以往的登录注册页面中,如果有输入错误,页面是重新刷新的,所以之前输入对的数据也会随之消失。
重复进行用户数据的校验:正则,长度,是否为空等等。
Form组件的解决方法:
先导入模块:
from django.forms import Form from django.forms import fields
后端:
from django.forms import Form from django.forms import fields class LoginForm(Form):
“““
字段的名称必须与前端的字典名称一致。
””” username = fields.CharField( max_length=18, min_length=6, required=True, error_messages={ "required":"用户名不能为空", "min_length":"长度不能小于6位", "max_length":"长度不能大于18位", } ) password = fields.CharField( min_length=16, required=True, error_messages={ "required": "密码不能为空", "min_length": "长度不能小于16位", } ) def login(request): if request.method == "GET": return render(request,"login.html") else: obj = LoginForm(request.POST) ret = obj.is_valid() #内部自动校验,ret是False和True的结果 if ret: #用户输入格式正确 print(obj.cleaned_data) #cleaned_data 是一个字典类型,是校验成功后拿到的值。 return redirect('http://www.baidu.com') else: #用户输入格式错误 # print(obj.errors) #所有的错误信息,这个错误信息是一个对象,是 __str__ 方法 # print(obj.errors["username"]) # print(obj.errors["username"][0]) #在LoginForm类中定义了多个条件,那么就可能有多个错误信息,所有可以用索引取第一个 # print(obj.errors["password"]) # print(obj.errors["password"][0]) return render(request,"login.html",{"obj":obj})
前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登录</h1> <form method="post" action="login.html"> {% csrf_token %} <p>username:<input type="text" name="username">{{ obj.errors.username.0 }}</p> <p>password:<input type="password" name="password">{{ obj.errors.password.0 }}</p> <input type="submit" value="submit"> </form> </body> </html>
到目前为止,Form组件的功能是对用户提交的数据进行校验和保留上次输入的内容。
对于前端用户提交的方式,有两种,一个是Form提交,一种是Ajax提交。
其中Form提交是刷新,并失去上次的输入内容。
而Ajax是不刷新,保留上次输入的内容。
Form的验证流程:
当执行is_valid的时候,Form的验证原理是:
1. 获取当期类中所有的字段,也就是LoginForm类中,我们定义的字段。
也就是当每次对LoginForm实例化的时候,会将LoginForm类中的字段放到self.fields中。这个self.fields 类似一个字典。
self.fields = {
"username":fields.CharField(required=Ture), #这个对象包含了这个正则表达式。
"password":fields.CharField(required=Ture), #这个对象包含了这个正则表达式。
}
2. 会循环self.fields,被循环的个数是由LoginForm来定的,因为self.fields循环的就是LoginForm的字段的个数。
for k,v in self.fields.items():
k:k是每次循环的username或password,它是字符串类型。
v:v是对应的正则表达式。
input_value = request.POST.get(k):这个表达式的意思是POST里有很多数据。
这里的k是字段的名字,如何写username,那么就会去找username的数据。
v的正则表达式的值和input_value的值进行校验。
所以在for循环之前,先定义一个flag=Ture.
当v的正则和input_value校验不匹配时,返回False的值。
flag = Ture for k,v in self.fields.items(): input_value = request.POST.get(k) flag = False return flag
以上的Form流程就是is_valid的原理。
is_valid 是True的话,获取cleaned_data的数据。
Form组件和Ajax的提交验证:
用Ajax的形式将前端的数据发送给后台:
前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用户登录</h1> <form id="f1" method="post" action="login.html"> {% csrf_token %} <p>username:<input type="text" name="username">{{ obj.errors.username.0 }}</p> <p>password:<input type="password" name="password">{{ obj.errors.password.0 }}</p> <input type="submit" value="submit"> <a onclick="submitForm();">提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm() { $.ajax({ url:"/ajax_login/", type:"POST", data:$("#f1").serialize(), //serialize()他会将所有的input框的数据打包交给data。这里打包的有csrf和username,password。效果是username=xxx&password=xxx&csrf=xxx,这是个字符串。 success:function (arg) { console.log(arg) } }) } </script> </body> </html>
后端代码:
def ajax_login(request): obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: print(obj.errors) return HttpResponse("...")
这样就算是提交错误了,页面是不会刷新,并且会保留之前输入的数据。
但这里我们实现代码会发现一个问题,那就是在错误提交数据后,也是不刷新啦,前端输入的值后端也拿到了,但是但是,有个问题点,就是前端的页面并没有错误提示呀。
所以,这个ajax的提交并不是那么的那么的完美,所以,我们接下来,就来完善一下这个ajax提交的错误提示。
Form组件和Ajax提交验证的显示错误信息:
这里用到了json.dumps的序列化操作,序列化的是obj.errors的对象。
前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用户登录</h1> <form id="f1" method="post" action="login.html"> {% csrf_token %} <p>username:<input type="text" name="username">{{ obj.errors.username.0 }}</p> <p>password:<input type="password" name="password">{{ obj.errors.password.0 }}</p> <input type="submit" value="submit"> <a onclick="submitForm();">提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm() { $('.c1').remove(); $.ajax({ url:"/ajax_login/", type:"POST", data:$('#f1').serialize(), //serialize()他会将所有的input框的数据打包交给data。这里打包的有csrf和username,password。效果是username=xxx&password=xxx&csrf=xxx,这是个字符串。 dataType:"JSON", success:function (arg) { console.log(arg); if(arg.status){ }else { $.each(arg.msg,function(index,value){ console.log(index,value); //index是对应的k的值,也就是username,value是username输入的值。 var tag = document.createElement("span"); tag.innerHTML = value[0]; tag.className = 'c1'; $('#f1').find('input[name="'+ index +'"]').after(tag); }) } } }) } </script> </body> </html>
后端代码:
def ajax_login(request): import json ret = {'status': True,'msg': None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: # print(obj.errors) # obj.errors对象 ret['status'] = False ret['msg'] = obj.errors v = json.dumps(ret) return HttpResponse(v)
这样就可以实现ajax提交有错误提示啦。
Form组件的常见字段和参数:
在XXXForm类中的字段:
数字类型:
#数字类型 number = fields.IntegerField(
min_value=10, #这里的min和max不是单纯的数字长度,而是数字范围。
max_value=1000,
#有错误信息 error_messages={ "required":"number不能为空", "invalid":"number格式错误,必须是数字", #invalid 格式错误
"min_value":"数值必须大于10",
"max_value":"数值必须小于1000", } )
邮件类型:
#邮件类型 Email = fields.EmailField( #有错误信息 error_messages={ "required":"Email不能为空", "invalid":"Email格式错误,必须是邮件格式", #invalid 格式错误 } )
还有对URL的fields.URLField。
还有fields.SlugField 和fields.GenericIPAddressField、fields.DateField、fields.DateTimeField。
但这些内置的也会有不完善的地方,无法达到我们的需求。所以,还有fields.RegesField。
可以用这个fields.RegesField去写正则表达式。
test = fields.RegesField('185\d+')
fields.RegesField是继承CharField的。
而CharField也是继承的Field,所以,我们来看一下Field的里的参数:
Form组件的Field类的参数:
widget 是用来指定生成什么样的HTML标签。比如select,text,input。
但用widget要先导入:from django.forms import widgets
label:写什么就在前端页面显示什么,在前端的写法是:
{{ obj.字段名.label }}
好比:
{{ obj.t1.label }}
initial:初始值。
在input框中显示默认值用的。
help_text:提供帮助信息:
在Form的字段中定义help_text: help_text='.......' 在前端代码和label一样: {{ obj.t1.help_text }} 这样就可以在前端显示:.......啦
validators:自定义验证规则
validators=[ ]
localize=False:是否支持本地化,这是用来转化时间的。
disabled=False:是否可以编辑。
label_suffix=None:label内容后缀。
上述这里参数,处理validators以外。其余的一起用,是可以自动生成HTML标签的。
这里就实现一个用后端参数实现一个前端标签的代码:
后端:
class TestForm(Form): t1 = fields.CharField( required=True, label="usename", label_suffix=":", help_text="输入username", disabled=False, initial="username", max_length=8, min_length=2, error_messages={ "required":"不能为空", "max_length":"long", "min_length":"短", } ) def login(request): if request.method =="POST": obj = TestForm() return render(request,"login.html",{"obj":obj}) else: obj = TestForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: print(obj.errors) return render(request,"login.html",{"obj":obj})
前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用户登录</h1> <form id="f1" method="post" action="login.html"> {% csrf_token %} <p> {{ obj.t1.label }}{{ obj.t1.label_suffix }} {{ obj.t1 }}{{ obj.t1.help_text }} </p> <input type="submit" value="submit"> </form> </body> </html>
以上就是用后端代码实现前端的标签的。
Form小总结:
form有验证的功能:
1.类:
字段 = 正则
2.is_valid()
form有生成HTML标签的功能:
1.类:
字段 = 正则( 正则这里规定一些生成HTML标签的特性)
2.is_valid()
Form组件保留上次输入的内容:
前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/register/" method="POST" novalidate> {% csrf_token %} <p>user: {{ obj.user }} {{ obj.errors.user.0 }} </p> <p>email: {{ obj.email }} {{ obj.errors.email.0 }} </p> <p>password: {{ obj.password }} {{ obj.errors.password.0 }} </p> <p>phone: {{ obj.phone }} {{ obj.errors.phone.0 }} </p> <input type="submit" value="提交" /> </form> </body> </html>
后端:
class RegiterForm(Form): user = fields.CharField(min_length=8) email = fields.EmailField() password = fields.CharField() phone = fields.RegexField('139\d+') def register(request): if request.method == 'GET': obj = RegiterForm() return render(request,'register.html',{'obj':obj}) #这个obj里是没有值的,因为是第一次的请求 else: obj = RegiterForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: print(obj.errors) return render(request,'register.html',{'obj':obj}) #这里的obj有值,值是input输入的值。
这样输入的值就可以保留。
Form组件小示例班级学生老师管理:
示例中,应用到的Form特性,以后在任何的提交数据和编辑数据中,都应该应用Form组件去完成,因为我们是不信任提交的数据的。
所有,需要用Form去做验证。
后端views代码:
from django.shortcuts import render,redirect from app01 import models from django.forms import Form from django.forms import fields from django.forms import widgets class ClassForm(Form): title = fields.RegexField('全栈\d+') def class_list(request): cls_list = models.Classes.objects.all() return render(request,'class_list.html',{'cls_list':cls_list}) def add_class(request): if request.method == "GET": obj = ClassForm() return render(request,'add_class.html',{'obj': obj}) else: obj = ClassForm(request.POST) if obj.is_valid(): # obj.cleaned_data # 字典 # 数据库创建一条数据 # print(obj.cleaned_data) # models.Classes.objects.create(title=obj.cleaned_data['tt']) models.Classes.objects.create(**obj.cleaned_data) return redirect('/class_list/') return render(request,'add_class.html',{'obj': obj}) def edit_class(request,nid): if request.method == "GET": row = models.Classes.objects.filter(id=nid).first() # 让页面显示初始值 # obj = ClassForm(data={'title': 'asdfasdfasdfas'}) obj = ClassForm(initial={'title': row.title}) return render(request,'edit_class.html',{'nid': nid,'obj':obj}) else: obj = ClassForm(request.POST) if obj.is_valid(): models.Classes.objects.filter(id=nid).update(**obj.cleaned_data) return redirect('/class_list/') return render(request,'edit_class.html',{'nid': nid,'obj':obj}) class StudentForm(Form): name = fields.CharField( min_length=2, max_length=6, widget=widgets.TextInput(attrs={'class': 'form-control'}) ) email = fields.EmailField(widget=widgets.TextInput(attrs={'class': 'form-control'})) age = fields.IntegerField(min_value=18,max_value=25,widget=widgets.TextInput(attrs={'class': 'form-control'})) cls_id = fields.IntegerField( # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')]) widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'}) ) def student_list(request): stu_list = models.Student.objects.all() return render(request,'student_list.html',{'stu_list':stu_list}) def add_student(request): if request.method == "GET": obj = StudentForm() return render(request,'add_student.html',{'obj':obj}) else: obj = StudentForm(request.POST) if obj.is_valid(): models.Student.objects.create(**obj.cleaned_data) return redirect('/student_list/') return render(request,'add_student.html',{'obj':obj}) def edit_student(request,nid): if request.method == "GET": row = models.Student.objects.filter(id=nid).values('name','email','age','cls_id').first() obj = StudentForm(initial=row) return render(request,'edit_student.html',{'nid':nid,'obj': obj}) else: obj = StudentForm(request.POST) if obj.is_valid(): models.Student.objects.filter(id=nid).update(**obj.cleaned_data) return redirect('/student_list/') return render(request,'edit_student.html',{'nid':nid,'obj': obj})
后端models代码:
from django.db import models class Classes(models.Model): title = models.CharField(max_length=32) class Student(models.Model): name = models.CharField(max_length=32) email = models.CharField(max_length=32) age = models.IntegerField(max_length=32) cls = models.ForeignKey('Classes') class Teacher(models.Model): tname = models.CharField(max_length=32) c2t = models.ManyToManyField('Classes')
URL:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^class_list/', views.class_list), url(r'^add_class/', views.add_class), url(r'^edit_class/(\d+)/', views.edit_class), url(r'^student_list/', views.student_list), url(r'^add_student/', views.add_student), url(r'^edit_student/(\d+)/', views.edit_student), ]
前端class_list 代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>班级列表</h1> <div> <a href="/add_class/">添加</a> </div> <ul> {% for row in cls_list %} <li>{{ row.title }} <a href="/edit_class/{{ row.id }}/">编辑</a> </li> {% endfor %} </ul> </body> </html>
前端add_class 代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>添加班级</h1> <form method="POST" action="/add_class/" novalidate> {% csrf_token %} {{ obj.title }} {{ obj.errors.title.0 }} <input type="submit" value="提交" /> </form> </body> </html>
前端edit_class 代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>编辑班级</h1> <form method="POST" action="/edit_class/{{ nid }}/"> {% csrf_token %} <p> {{ obj.title }} {{ obj.errors.title.0 }} </p> <input type='submit' value="提交" /> </form> </body> </html>
前端student_list 代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>学生列表</h1> <a href="/add_student/">添加</a> <ul> {% for row in stu_list %} <li>{{ row.name }}-{{ row.email }}-{{ row.age }}-{{ row.cls_id }}-{{ row.cls.title }} <a href="/edit_student/{{ row.id }}/">编辑</a></li> {% endfor %} </ul> </body> </html>
前端add_student 代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>添加学生</h1> <form action="/add_student/" method="POST"> {% csrf_token %} <p> {{ obj.name }} </p> <p> {{ obj.email }} </p> <p> {{ obj.age }} </p> <p> {{ obj.cls_id }} </p> <input type="submit" value="提交" /> </form> </body> </html>
前端edit_student 代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="/static/bootstrap-3.3.5-dist/css/bootstrap.css"/> </head> <body> <div style="width: 500px;margin: 0 auto;"> <form class="form-horizontal" method="POST" action="/edit_student/{{ nid }}/"> {% csrf_token %} <div class="form-group"> <label class="col-sm-2 control-label">姓名:</label> <div class="col-sm-10"> {{ obj.name }} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">邮箱:</label> <div class="col-sm-10"> {{ obj.email }} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">年龄:</label> <div class="col-sm-10"> {{ obj.age }} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">班级:</label> <div class="col-sm-10"> {{ obj.cls_id }} </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <input type="submit" class="btn btn-default" value="提交" /> </div> </div> </form> </div> </body> </html>
老师多对多:
注意:
Select框: 单选 cls_id = fields.IntegerField( # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')]) widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'}) ) cls_id = fields.ChoiceField( choices=models.Classes.objects.values_list('id','title'), widget=widgets.Select(attrs={'class': 'form-control'}) ) obj = FooForm({'cls_id':1}) 多选 xx = fields.MultipleChoiceField( choices=models.Classes.objects.values_list('id','title'), widget=widgets.SelectMultiple ) obj = FooForm({'cls_id':[1,2,3]})
老师的models 代码:
from django.db import models class Classes(models.Model): title = models.CharField(max_length=32) def __str__(self): return self.title class Student(models.Model): name = models.CharField(max_length=32) email = models.CharField(max_length=32) age = models.IntegerField() cls = models.ForeignKey('Classes') class Teacher(models.Model): tname = models.CharField(max_length=32) """ 10 """ c2t = models.ManyToManyField('Classes')
老师的view后端代码:
def teacher_list(request): tea_list = models.Teacher.objects.all() return render(request,'teacher_list.html',{'tea_list':tea_list}) from django.forms import models as form_model class TeacherForm(Form): tname = fields.CharField(min_length=2) # xx = form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all()) # xx = form_model.ModelChoiceField(queryset=models.Classes.objects.all()) xx = fields.MultipleChoiceField( # choices=models.Classes.objects.values_list('id','title'), widget=widgets.SelectMultiple ) def __init__(self,*args,**kwargs): super(TeacherForm,self).__init__(*args,**kwargs) self.fields['xx'].choices = models.Classes.objects.values_list('id','title') # obj = TeacherForm() # 1. 找到所有字段 # 2. self.fields = { # tname: fields.CharField(min_length=2) # } def add_teacher(request): if request.method == "GET": obj = TeacherForm() return render(request,'add_teacher.html',{'obj':obj}) else: obj = TeacherForm(request.POST) if obj.is_valid(): xx = obj.cleaned_data.pop('xx') row = models.Teacher.objects.create(**obj.cleaned_data) row.c2t.add(*xx) # [1,2] return redirect('/teacher_list/') return render(request,'add_teacher.html',{'obj':obj}) def edit_teacher(request,nid): if request.method == "GET": row = models.Teacher.objects.filter(id=nid).first() class_ids = row.c2t.values_list('id') # print(class_ids) # id_list = [] id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else [] # obj = TeacherForm(initial={'tname':row.tname,'xx':[1,2,3]}) obj = TeacherForm(initial={'tname':row.tname,'xx':id_list}) return render(request,'edit_teacher.html',{'obj':obj})
老师的teacher_list 前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>老师列表</h1> <div> <a href="/add_teacher/">添加</a> </div> <table border="1"> <thead> <tr> <th>ID</th> <th>老师姓名</th> <th>任教班级</th> <th>编辑</th> </tr> </thead> <tbody> {% for row in tea_list %} <tr> <td>{{ row.id }}</td> <td>{{ row.tname }}</td> <td> {% for item in row.c2t.all %} <span>{{ item }}</span> {% endfor %} </td> <td> <a href="/edit_teacher/{{ row.id }}/">编辑</a> </td> </tr> {% endfor %} </tbody> </table> </body> </html>
老师的add_teacher 前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form method="POST" action="/add_teacher/"> {% csrf_token %} <p> 姓名:{{ obj.tname }} </p> <p> 班级:{{ obj.xx }} </p> <input type="submit" value="提交" /> </form> </body> </html>
老师的edit_teacher 前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>编辑老师</h1> <form> {{ obj.tname }} {{ obj.xx }} </form> </body> </html>
Form组件的常用组件:
CheckBox复选框的应用:
test后端:
class TestForm(Form): t1 = fields.CharField( widget=widgets.Textarea(attrs={}) ) t2 = fields.CharField( #单选的 widget=widgets.CheckboxInput ) t3 = fields.MultipleChoiceField( #多选 choices=[(1,'篮球'),(2,'足球'),(3,'溜溜球')], widget=widgets.CheckboxSelectMultiple ) t4 = fields.ChoiceField( #单选,选择互斥 choices=[(1,'篮球'),(2,'足球'),(3,'溜溜球')], widget=widgets.RadioSelect ) t5 = fields.FileField( #上传文件 widget=widgets.FileInput )
def test(request): obj = TestForm(initial={'t3':[2,3]}) #默认选中 obj.is_valid() return render(request,'test.html',{'obj':obj})
test前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> {{ obj.t2 }} {{ obj.t3 }} {{ obj.t4 }} {{ obj.t5 }} </body> </html>
Form验证执行流程和钩子:
is_valid方法的内部流程:
is_valid的里面有一个return的返回,返回的有self.is_bound 和 self.errors。
这个self.is_bound是只有True和False两个值,在初始化的时候,会进行校验,这个校验的值就是True 和 False。
在self.errors里面有一个self.full_clean方法,这个方法就是去做验证的。这个验证就是循环Form自己的字段,
然后去提交的数据进行校验。
在self.full_clean里面,我们可以看到有cleaned_data,这就是我们的校验数据,这是一个字典类型。
最后是clean_fields处理data的数据。
self._clean_fields() #做cleaned_data数据处理用
self._clean_form() #做钩子用
self._post_clean()
钩子:是自己定义的,当定义的钩子函数被调用是当每一个字段,自己的正则表达式,自己的函数后执行完,才会执行这个钩子函数。
如果想用钩子函数,那么cleaned_data里是已经有值的啦。
样例:
from django.core.exceptions import ValidationError class TestForm(Form): user = fields.CharField(validators=[]) pwd = fields.CharField() def clean_user(self): v = self.cleaned_data['user'] if models.Student.objects.filter(name=v).count(): raise ValidationError('用户名已经存在') return self.cleaned_data['user'] def clean_pwd(self): return self.cleaned_data['pwd'] def clean(self): #钩子 # user = self.cleaned_data.get('user') # email = self.cleaned_data.get('email') # if models.Student.objects.filter(user=user,email=email).count(): # raise ValidationError('用户名和邮箱联合已经存在') return self.cleaned_data
# def _post_clean(self): # """ # An internal hook for performing additional cleaning after form cleaning # is complete. Used for model validation in model forms. # """ # pass
Form扩展:
字段 = 默认的正则表达式。
在默认的正则中,可以在加额外的正则,用validators=[]
clean_字段 = 必须有返回值。
clean():有返回值,用定义的返回值 cleaned_data = 返回值。
没有返回值,用原来的值,cleaned_data = 原有的值。
Form的验证流程:
1. 写一个Form,用户提供大量的验证数据,先一个一个字段的去获取。
2. 拿一个字段,做自己的正则,当自己的正则执行完,就执行自己的函数。
3. 所有的字段执行完自己函数后,执行clean()方法。
Form组件总结:
1. 使用
class Foo:
xx = xxxxxx() # 正则,插件
def clean_xx():
...
def clean():
pass
2. 页面展示
obj = Foo()
# 灵活
<form>
{{obj.xx}}
{{obj.xx}}
{{obj.xx}}
</form>
# 简单
{{obj.as_p}}
<ul>
{{obj.as_ul}}
</ul>
<table>
{{obj.as_table}}
</table>
3. 后台
is_valid()
clean_data
errors
参考blog:XXXXXXXX6144178.html
------- END -------