表结构
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(verbose_name='用户名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
tel = models.CharField(verbose_name='电话号码(中国)', max_length=11, null=True)
email = models.EmailField(verbose_name='邮箱', null=True)
def __str__(self):
return self.username
主要围绕用户注册,登录做表单校验
传统表单校验
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<style>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
background-color: #f0eeee;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
form {
width: 600px;
background-color: white;
border-radius: 5px;
padding: 40px 80px;
box-shadow: 0 0 5px rgba(33, 33, 33, 0.2);
}
form .title {
text-align: center;
}
form input[type="submit"] {
margin-top: 10px;
width: 100%;
}
</style>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<h2 class="title">用户注册</h2>
<div class="form-group">
<label for="name">用户名:</label>
<input type="text" name="username" id="name" class="form-control" placeholder="请输入用户名">
</div>
<div class="form-group">
<label for="pwd">密码:</label>
<input type="text" name="password" id="pwd" class="form-control" placeholder="请输入密码">
</div>
<div class="form-group">
<label for="re_pwd">确认密码:</label>
<input type="text" name="re_pwd" id="re_pwd" class="form-control" placeholder="请输入确认密码">
</div>
<div class="form-group">
<label for="email">请输入邮箱:</label>
<input type="email" name="email" id="email" class="form-control" placeholder="请输入邮箱">
</div>
<div class="form-group">
<label for="tel">请输入手机号:</label>
<input type="tel" name="tel" id="tel" class="form-control" placeholder="请输入手机号">
</div>
<div class="form-group">
<input type="submit" value="提交" class="btn btn-success">
</div>
</form>
</body>
</html>
后台验证逻辑
from django.shortcuts import render, HttpResponse
from app01.models import UserInfo
import re
def index(request):
if request.method == 'POST':
# 本身的QueryDict是不可变的,复制一份就可以变了
data: dict = request.POST # 获取 POST 请求的数据
name = data.get('username')
if not name:
# 为空校验
return HttpResponse('用户名不能为空')
# 用户名长度校验
if len(name) > 8:
return HttpResponse('用户名不能超过八字符')
pwd = data.get('password')
if not pwd:
# 为空校验
return HttpResponse('密码不能为空')
extra = {
'username': name,
'password': pwd,
} # 构造要添加的数据
if not re.match(r'^[\w_-]{6,16}$', pwd):
# 最短6位,最长16位 可以包含小写大母和大写字母可以包含数字可以包含下划线和减号
return HttpResponse('密码强度不符合要求')
re_pwd = data.get('re_pwd')
if not re_pwd:
# 为空校验
return HttpResponse('请输入确认密码')
email = data.get('email')
# 可以不输入邮箱,但是只要输入就要满足邮箱的规则
if not re.match(r'^\w+@\w+\.\w+|$', email):
return HttpResponse('此邮箱不合法')
if email:
extra['email'] = email
tel = data.get('tel')
if not re.match(r'^1\d{10}|$', tel):
return HttpResponse('请输入正确的手机号')
if tel:
extra['tel'] = tel
# 校验两次密码是否一致
if pwd != re_pwd:
return HttpResponse('两次密码不一致')
# 规则全部校验成功,添加数据到数据库
UserInfo.objects.create(**extra)
return HttpResponse('登录成功')
return render(request, 'index.html', locals())
可以看到,验证逻辑全部写在视图函数里面真的是又臭又长,而且对于代码的可复用性简直就是负数
很致命的问题是校验错误之后,错误信息是直接单独出现在页面
我们需要的是那个字段校验不通过就出现在那个字段的下面
所以有没有一种很方便又可以复用的表单验证的组件呢?
Forms组件是什么?
我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来.
与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等是否正确…
如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息
Django form组件就实现了上面所述的功能, forms组件的主要功能如下:
渲染页面标签
校验字段
保留用户的输入并渲染错误信息
在用到forms组件的之前首先需要定义forms组件, 然后才能使用.
接下来以注册学生作为示例
注册学生本质就是往student表中添加记录
如果我添加的数据不符合要求,应该给前端发送提示信息,并且数据不能添加进去
Form定义
要定义Form组件, 需要与前端传递过来的字段一一对应
from django.shortcuts import render, HttpResponse
from app01.models import UserInfo
from django import forms
from django.core.validators import RegexValidator
class UserInform(forms.Form):
username = forms.CharField(max_length=8)
password = forms.CharField(max_length=16, min_length=6)
email = forms.EmailField(required=False) # 可以不输入
tel = forms.CharField(validators=[
RegexValidator(r'^1\d{10}$', '请输入正确的手机号码') # 自定义校验规则
], required=False)
def index(request):
if request.method == 'POST':
data: dict = request.POST # 获取 POST 请求的数据
form = UserInform(data)
if not form.is_valid():
# 校验不通过
print(form.errors) # 校验失败的错误信息
return render(request, 'index.html', locals())
# 校验通过
print(form.cleaned_data) # 校验成功之后的数据
return render(request, 'index.html', locals())
定义一个类 取名一般叫做 表名需求Form 如:
添加学生:StudentAddForm
编辑学生信息:StudentInfoEditForm
添加班级:ClassesAddForm
然后就可以在类中定义我们需要校验的字段,和校验的规则
forms内置字段
required=False, 是否允许为空
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)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
这些用的都不是很多,了解几个即可
显示错误信息
默认的错误信息是英文,或者是一一些系统定义的错误信息
我们可以将django语言更改为中文语言
django中文设置
在django的配置文件中,更改这两项
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
如果你报错了,一定是你名字写错了
网上很多django更改语言的文章,都是乱搞!
修改成功之后,错误信息就是中文了
自定义错误信息
from django import forms
from django.core.validators import RegexValidator
class UserInform(forms.Form):
username = forms.CharField(
max_length=8,
error_messages={
'required': '姓名不能为空', 'invalid': '请输入正确的名字'
}
)
password = forms.CharField(
max_length=16, min_length=6,
error_messages={
'required': '请输入密码', 'min_length': '密码最低6位', 'max_length': '密码超过16位'
}
)
re_pwd = forms.CharField(
max_length=16, min_length=6,
error_messages={
'required': '请输入确认密码', 'min_length': '密码最低6位', 'max_length': '密码超过16位'
}
)
email = forms.EmailField(
required=False,
error_messages={
'invalid': '请输入正确的邮箱'
}
)
tel = forms.CharField(validators=[
RegexValidator(r'^1\d{10}$', '请输入正确的手机号码') # 自定义校验规则
], required=False)
用的比较多的就这些了
required:为空错误
min_length:小于某个长度错误
max_length:大于某个长度错误
invalid:校验不通过的错误
显示错误信息到页面
校验不通过时,将错误信息显示到对应字段中
同时要保留我输入的内容
html
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<style>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
background-color: #f0eeee;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
form {
width: 600px;
background-color: white;
border-radius: 5px;
padding: 40px 80px;
box-shadow: 0 0 5px rgba(33, 33, 33, 0.2);
}
form .title {
text-align: center;
}
form input[type="submit"] {
margin-top: 10px;
width: 100%;
}
</style>
</head>
<body>
<form action="" method="post" data-options="novalidate:true">
{% csrf_token %}
<h2 class="title">用户注册</h2>
<div class="form-group">
<label for="name">用户名:</label>
<input type="text" name="username" value="{{ data.username }}" id="name" class="form-control" placeholder="请输入用户名">
<span class="errors">{{ error.username }}</span>
</div>
<div class="form-group">
<label for="pwd">密码:</label>
<input type="text" name="password" value="{{ data.password }}" id="pwd" class="form-control" placeholder="请输入密码">
<span class="errors">{{ error.password }}</span>
</div>
<div class="form-group">
<label for="re_pwd">确认密码:</label>
<input type="text" name="re_pwd" value="{{ data.re_pwd }}" id="re_pwd" class="form-control" placeholder="请输入确认密码">
<span class="errors">{{ error.re_pwd }}</span>
</div>
<div class="form-group">
<label for="email">请输入邮箱:</label>
<input type="text" name="email" value="{{ data.email }}" id="email" class="form-control" placeholder="请输入邮箱">
<span class="errors">{{ error.email }}</span>
</div>
<div class="form-group">
<label for="tel">请输入手机号:</label>
<input type="tel" name="tel" value="{{ data.tel }}" id="tel" class="form-control" placeholder="请输入手机号">
<span class="errors">{{ error.tel }}</span>
</div>
<div class="form-group">
<input type="submit" value="提交" class="btn btn-success">
</div>
</form>
</body>
</html>