django的forms认证组件
每个网站的注册界面都需要有相应的“认证”功能,比如说认证注册页面的用户名是否已被注册,二次输入的密码是否一致以及认证用户输入的用户名、邮箱、手机号等字段是否符合程序员所指定的“规则”等等。当然,不同的web框架有不同的实现方式,本文介绍django的forms组件的实现方法。
默认的校验规则
默认的校验规则都是校验单个字段而且格式是固定的:
建表
models.py文件为数据库中创建下面字段:
from django.db import models
class UserInfo(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
email = models.EmailField()
tel = models.CharField(max_length=32)
模板文件
模板文件我们引用bootstrap,并且利用模板语言进行渲染得到相应的页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Forms组件</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css">
<link rel="stylesheet" href="/static/whw_css.css">
</head>
<body>
<h3>注册页面</h3>
<div class="container">
<div class="row">
<div class="col-md-6 col-lg-offset-3">
<form action="" method="post" novalidate >
{% csrf_token %}
<p>用户名 {{ form.name }}<span class="pull-right">{{ form.name.errors.0 }}</span></p>
<p>密码 {{ form.pwd }}<span class="pull-right">{{ form.pwd.errors.0 }}</span></p>
<p>确认密码 {{ form.r_pwd }}<span class="pull-right">{{ form.r_pwd.errors.0 }}</span><span class="pull-right">{{ full_errors.0 }}</span></p>
<p>邮箱 {{ form.email }}<span class="pull-right">{{ form.email.errors.0 }}</span></p>
<p>手机号 {{ form.tel }}<span class="pull-right">{{ form.tel.errors.0 }}</span></p>
<input type="submit" value="确认">
</form>
</div>
</div>
</div>
</body>
</html>
校验模块
为了使程序易于维护且解耦性高一点,我们把认证功能写在一个模块my_forms.py
里,在里面定义一个专门用于认证的类UserForm
:
#先引入相应的模块
from django import forms
from django.forms import widgets
from app01.models import UserInfo
from django.core.exceptions import NON_FIELD_ERRORS,ValidationError
#做校验的类,后面跟着校验规则
class UserForm(forms.Form):
##校验字段
name = forms.CharField(min_length=4,label='用户名',widget=widgets.TextInput(attrs={'class':'form-control'}),error_messages={'required':'输入不能为空'})
email = forms.EmailField(label='邮箱',widget=widgets.TextInput(attrs={'class':'form-control'}),error_messages={'required':'输入不能为空','invalid':'请输入邮箱格式'})
pwd = forms.CharField(min_length=4,label='密码',widget=widgets.PasswordInput(attrs={'class':'form-control'}),error_messages={'required':'输入不能为空'})
r_pwd = forms.CharField(min_length=4,label='确认密码',widget=widgets.PasswordInput(attrs={'class':'form-control'}),error_messages={'required':'输入不能为空'})
tel = forms.CharField(label='手机号',widget=widgets.TextInput(attrs={'class':'form-control'}),error_messages={'required':'输入不能为空'})
参数说明:
(1)min_length=4表示输入的字符的长度不能小于4
(2)widget=widgets.TextInput(attrs={'class':'form-control'}) 这句话表示输入框input的type='text',且class='form-control'
(3)error_messages是在用户输入不符合校验规则时做出的说明,是一个字典的形式。注意字典里的key值是固定的!
视图函数
views.py文件的内容如下:
from django.shortcuts import render,HttpResponse
##引入校验的类
from app01.my_forms import UserForm
#视图函数
def my_forms(request):
if request.method == 'GET':
form = UserForm()
return render(request, 'index.html',{'form':form})
if request.method == 'POST':
#form表单的name属性值应当与forms组件的字段名称一致
form = UserForm(request.POST)
print(form.is_valid())
if form.is_valid():
print(form.cleaned_data)
#只有全部验证成功了才执行
return HttpResponse('OK!')
else:
print(form.errors)
#带着参数返回当前页面
return render(request,'index.html',locals())
如上面的代码所示,我们用UserForm
类以及前端返回的参数
实例化出一个类form
:
form = UserForm(request.POST)
这里有一个is_valid()
方法,返回布尔类型的值。只有当全部字段校验成功后它的值才为True。
最终校验成功的字段存到了form.cleaned_data
里;校验失败的字段以及对应的错误信息放在了form.errors
里。将这两个“字典”类型的数据传给模板我们就可以看到对应的信息了:
自定义校验规则与多个字段的校验
一、自定义校验规则我们用到局部钩子
。如果我们想校验属性name,那么可以在UserForm
类中我们定义一个方法,名字固定为clean_name
:
##校验数据库中是否有相同的用户名
def clean_name(self):
val = self.cleaned_data.get('name')
#数据库中检测
ret = UserInfo.objects.filter(name=val)
if not ret:
return val
#如果ret有值表示数据库中有这条记录了
else:
raise ValidationError('该用户已注册')
注意这个方法名固定,必须是clean_%s
的形式,这里的%s
就是校验的属性的名字。比如说我们想校验手机号必须为11位可以这样写:
def clean_tel(self):
val = self.cleaned_data.get('tel')
if len(val) == 11:
return val
else:
raise ValidationError('手机号必须为11位')
二、进行多个字段的校验我们用到全局钩子
如果我们想校验两次收入的密码是否一致可以在UserForm
中定义一个方法clean
:
def clean(self):
pwd = self.cleaned_data.get('pwd')
r_pwd = self.cleaned_data.get('r_pwd')
if pwd and r_pwd:
if pwd == r_pwd:
return self.cleaned_data
else:
raise ValidationError('两次密码不一致')
else:
return self.cleaned_data