#form表单的校验、局部钩子及全局钩子#
## views.py 视图函数 ##
from django import forms #调用forms模块 from django.forms import widgets #调用widgets模块,用来对form组件的参数配置。 from django.core.exceptions import ValidationError #调用 ValidationError 模块。用来手动触发raise错误。 from fileupdate.models import * #载入必要的数据库列表。 class FormReg(forms.Form): name = forms.CharField(min_length=4, widget=widgets.TextInput(attrs={'class': 'form-control '}), label='姓名', error_messages={'required': '*不能为空', }) pwd = forms.CharField(min_length=4, widget=widgets.PasswordInput(attrs={'class': 'form-control'}), label='密码') r_pwd = forms.CharField(min_length=4, widget=widgets.PasswordInput(attrs={'class': 'form-control'}), label='确认密码') email = forms.EmailField(widget=widgets.EmailInput(attrs={'class': 'form-control'}), label='邮箱') tel = forms.CharField(max_length=13, label='电话', widget=widgets.TextInput(attrs={'class': 'form-control'})) ##字段的校验,通过对widget的属性设置,可定义INPUT标签的type类型,以及标签的其他属性。通过对label设置,可以自定义form渲染时的标签名, ##另外,通过对error_messages属性设置,可对验证信息进行自定义。注意:字典中错误信息的key值是固定的 def clean_name(self): #局部钩子 注意:名字必须为clean_%s ,这是根据源码来设置的。 #其原理是,当字段校验完毕后,再进行查找是否有以clean_开头的函数名,如果有,就调用该函数, #运行我们自定义的函数,如果满足条件就返回当前被校验字段的内容。否则手动触发ValidationError错误,源码中会捕获并将值返回。 val = self.cleaned_data.get('name') #通过cleaned_data获得对应字段的'干净数据' user_obj = User.objects.filter(name=val).first() #与对应的数据库中字段相比较,并获得一个字段对象 if not user_obj: #对字段进行判断,如果为空(数据库中没有对应的名字),那么返回这个校验值。 return val else: raise ValidationError('名字存在') #如果存在,那么手动触发异常(异常名为ValidationError),并设置自定义内容。 def clean(self): #全局钩子 注意:名字必须为clean,这是根据源码来设置的。 #其原理是对校验完毕的字段,再进行字段间的校验。当字段校验完毕,查找是否有clean的函数,如果有就运行该 #函数,其功能是对所有校验的字段进行校验比对。如果满足条件,就将cleaned_data返回(这与源码相匹配) #如果不满足就手动触发ValidationError错误。 pwd = self.cleaned_data.get('pwd') r_pwd = self.cleaned_data.get('r_pwd') if pwd and r_pwd: #如果两个字段中一个为空值那么就不用再进行校验。直接返回cleaned_data,通过校验功能返回错误信息。 if pwd == r_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致!') else: return self.cleaned_data def reg(request): if request.method == 'POST': #如果是一次POST提交,那么进行校验。 formreg = FormReg(request.POST) #对提交的信息实例化。 if formreg.is_valid(): #通过is_valid()方法进行判断,(注意:当执行这个函数时,将对所有字段进行校验,运行局部钩子和全局钩子) return HttpResponse('OK') else: print('cleaneddata', formreg.cleaned_data) print('errordata', formreg.errors) error = formreg.errors.get('__all__') #当设置了全局钩子时,要设置一个变量来获得全局钩子返回的错误信息。 #这是由于,全局钩子的错误在form对象的errors中,当clean()方法抛出异常时,源码会自动捕获,并将错误 #存储在errors字典中,其中键名'__all__'就是全局钩子的变量。 return render(request, 'reg.html', locals()) formreg = FormReg() #当为get请求时,实例化一个空的对象,通过这个空的实例化对象可以渲染前段,自动生成form表单。 return render(request,'reg.html', locals())
## reg.html 前端页面 ##
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>reg</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in formreg %} <p> <label for="">{{ field.label }}</label> {{ field }} {% if field.name == 'r_pwd' %} <span style="color: crimson">{{ field.errors.0 }} {{ error.0 }}</span> {% else %} <span style="color: crimson">{{ field.errors.0 }}</span> {% endif %} </p> {% endfor %} <p><input type="submit"></p> </form> </div> </div> </div> </body> </html>