十八.用户注册 ---- 用户名/用户密码/手机号验证
引言
注:该篇文章接上一篇 十七.用户注册 ---- 图形验证码
在上一篇文章我们实现了用户注册中的图形验证码过程,接下来我们要实现用户名验证,密码验证,以及手机号验证.
实现注册要完成的图表
实现注册模块的整体流程
根据流程图总结注册业务包含如下功能
- 注册页面
- 图片验证码
- 用户名检测是否注册
- 手机号检测是否注册
- 短信验证码
- 注册保存用户数据
五.json响应数据结构设计
JSON数据现在是我们开发中用的最多的,百分之九十的数据都是通过JSON方式进行传输.
1.结构设计
实际项目是多人协同开发,特别是前后端交互,后端返回数据结构要一致。
{"errno": "0", "errmsg": "OK", "data": {...}}
字段 | 类型 | 说明 |
---|---|---|
errno | 字符串 | 错误编码 |
errmsg | 字符串 | 错误信息 |
data | 返回数据 |
在项目根目录中utils文件夹下创建res_code.py文件,用于定义错误编码,代码如下:
class Code:
OK = "0"
DBERR = "4001"
NODATA = "4002"
DATAEXIST = "4003"
DATAERR = "4004"
METHERR = "4005"
SMSERROR = "4006"
SMSFAIL = "4007"
SESSIONERR = "4101"
LOGINERR = "4102"
PARAMERR = "4103"
USERERR = "4104"
ROLEERR = "4105"
PWDERR = "4106"
SERVERERR = "4500"
UNKOWNERR = "4501"
error_map = {
Code.OK: "成功",
Code.DBERR: "数据库查询错误",
Code.NODATA: "无数据",
Code.DATAEXIST: "数据已存在",
Code.DATAERR: "数据错误",
Code.METHERR: "方法错误",
Code.SMSERROR: "发送短信验证码异常",
Code.SMSFAIL: "发送短信验证码失败",
Code.SESSIONERR: "用户未登录",
Code.LOGINERR: "用户登录失败",
Code.PARAMERR: "参数错误",
Code.USERERR: "用户不存在或未激活",
Code.ROLEERR: "用户身份错误",
Code.PWDERR: "密码错误",
Code.SERVERERR: "内部错误",
Code.UNKOWNERR: "未知错误",
}
2.快捷方法
为了方便定义一个快捷方法,在utils目录下创建json_res.py文件代码如下:
from django.http import JsonResponse
from .res_code import Code
def json_response(errno=Code.OK, errmsg='', data=None, kwargs=None):
json_dict = {
'errno': errno,
'errmsg': errmsg,
'data': data
}
#判断kwargs 是否为字典类型
if kwargs and isinstance(kwargs, dict) :
#把数据添加到json_dict字典中
json_dict.update(kwargs)
#把字典转为json格式返回
return JsonResponse(json_dict)
默认情况下JsonResponse只能对字典进行dumps,如果想要对非字典的数据进行dumps,那么需要给JsonResponse传递一个safe=False参数。
六、判断用户是否注册功能实现
1.接口设计
接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /username/(?P\w{5,20})/ |
参数格式 | url路径参数 |
参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
username | 字符串 | 是 | 输入的用户名 |
在调用接口返回的结果为:
- 用户名:在前端输入的用户名
- 用户数量:用用户名在数据库中查询的用户数量
{
"errno": "0",
"errmsg": "OK",
"data": {
"username": "username", # 查询的用户名
"count": 1 # 用户名查询的数量
}
}
2.接口实现后端代码
1.在已经创建好的app verification 中处理验证
2.在verification/views.py代码
from user.models import User
from utils.json_res import json_response
def check_username_view(request, username):
#去数据库查询数据,然后返回就好了
data = {
‘errno':'0',
'errmsg':'OK',
'data':{
'username': username, #需要查询的用户名
'count': User.objects.filter(username=username).count() #询用户数量
}
}
return json_response(data=data)
查询用户数为零–可以注册
查询用户数不为零–不可以注册
2.verification/urls.py代码
re_path和path的区别
re_path('username/(?P<username>\w{5,20})/', views.check_username_view, name='check_username'),
使用re_path 匹配方式,?P< username >\w{5,20})/ --用户名满足5-20位
from django.urls import path, re_path
from . import views
# url的命名空间
app_name = 'verification'
urlpatterns = [
path('image_code/', views.image_code_view, name='image_code'),
re_path('username/(?P<username>\w{5,20})/', views.check_username_view, name='check_username'),
]
3.前端页面代码
user/register.html(注册页面)代码如下:
在用户名处添加:
id="username"
为什么不删除"name"="username"
1.在html中id具有唯一性,方便查询
2. "name"="username"
是项目模板中自带的,可能与其他的地方对应,删除以后有可能造成不必要的错误
user/register.html(注册页面)代码如下:
{% extends 'base/base.html' %}
{% load static %}
{% block title %}注册{% endblock title %}
{% block link %}
<link rel="stylesheet" href="{% static 'css/user/auth.css' %}">
{% endblock link %}
{% block main_start %}
<main id="container">
<div class="register-contain">
<div class="top-contain">
<h4 class="please-register">请注册</h4>
<a href="javascript:void(0);" class="login">立即登录 ></a>
</div>
<form action="" method="post" class="form-contain">
<div class="form-item">
<input type="text" placeholder="请输入用户名" id="username" name="username" class="form-control" >
</div>
<div class="form-item">
<input type="password" placeholder="请输入密码" name="password" class="form-control">
</div>
<div class="form-item">
<input type="password" placeholder="请输入确认密码" name="password_repeat" class="form-control">
</div>
<div class="form-item">
<input type="tel" placeholder="请输入手机号" name="telephone" class="form-control" autocomplete="off">
</div>
<div class="form-item">
<input type="text" placeholder="请输入图形验证码" name="captcha_graph" class="form-captcha">
<a href="javascript:void(0);" class="captcha-graph-img">
<img src="{% url 'verification:image_code' %}" alt="验证码" title="点击刷新">
</a>
</div>
<div class="form-item">
<input type="text" placeholder="请输入短信验证码" name="sms_captcha" class="form-captcha" autocomplete="off">
<a href="javascript:void(0);" class="sms-captcha" title="发送验证码">获取短信验证码</a>
</div>
<div class="form-item">
<input type="submit" value="立即注册" class="register-btn">
</div>
</form>
</div>
</main>
{% endblock main_start %}
{% block script %}
<script src="{% static 'js/user/auth.js' %}"></script>
{% endblock script %}
4.前端js代码
base/base.html
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script src="{% static 'js/base/common.js' %}"></script>
<script src="{% static 'js/base/message.js' %}"></script>
user/register.html 第20行
<input type="text" placeholder="请输入用户名" id="username" name="username" class="form-control" >
user/auth.js代码:
关于js代码中的.$ajax()
用法: $.ajax()方法详解
$(function () {
// 定义状态变量
//判断状态是false还是ture,如果是ture就直接引用
let isUsernameReady = false,
isPasswordReady = false,
isMobileReady = false,
isSmsCodeReady = false;
let $img = $('.form-contain .form-item .captcha-graph-img img');
// 1.点击刷新图像验证码
$img.click(function () {
$img.attr('src', '/image_code/?rand=' + Math.random())
});
// 2.鼠标离开用户名输入框校验用户名
let $username = $('#username'); //获取前端页面中的username框
$username.blur(fnCheckUsername); //blur是鼠标离开事件
//鼠标离开username触发函数fnCheckUsername
function fnCheckUsername() {
isUsernameReady = false; //校验用户名,没填入用户名为false
let sUsername = $username.val(); // 获取用户名字符串
if (sUsername === '') {
// 如果用户名为空,返回消息
message.showError('用户名不能为空')
return
}
if (!(/^\w{5,20}$/).test(sUsername)) {
//检测用户名长度
message.showError('请输入5-20个字符的用户名');
return
}
$.ajax({
url: '/username/' + sUsername + '/', //发送请求的地址
type: 'GET', //请求方式
dataType: 'json', //预期服务器返回的数据类型
success: function (data) {
// data 由服务器返回的数据,我们这里是json类型
if (data.data.data.count !== 0) {
//根据json的数据结构的到用户数量
message.showError(data.data.data.username + '已经注册,请重新输入!')
} else {
message.showInfo(data.data.username + '可以正常使用!');
isUsernameReady = true
}
},
error: function (xhr, msg) {
//请求失败时被调用的函数
message.showError('服务器超时,请重试!')
}
});
}
// 3.检测密码是否一致
let $passwordRepeat = $('input[name="password_repeat"]'); //获取前端input[name="password_repeat"] 中的内容(二次密码)
$passwordRepeat.blur(fnCheckPassword); //blur是鼠标离开事件
//鼠标离开username触发函数fnCheckPassword
function fnCheckPassword() {
isPasswordReady = false; //校验密码,没填入密码为false
let password = $('input[name="password"]').val(); // 获得密码字符串
let passwordRepeat = $passwordRepeat.val(); // 获取用户二次密码字符串
if (password === '' || passwordRepeat === '') {
message.showError('密码不能为空');
return
}
if (password !== passwordRepeat) {
message.showError('两次密码输入不一致');
return
}
if (password === passwordRepeat) {
isPasswordReady = true
}
}
});
5.运行结果
1.关于后端json的返回数据测试
2.对于前端代码测试:
七、判断手机号码是否注册功能
1.接口设计
接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /mobile/(?P\1[3-9]\d{9})/ |
参数格式 | url路径参数 |
参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
moblie | 字符串 | 是 | 输入的手机号码 |
返回结果:
{
"errno": "0",
"errmsg": "OK",
"data": {
"mobile": "13xxxxxxxxx", # 查询的手机号
"count": 1 # 手机号查询的数量
}
}
2.后端代码
- verification/views.py代码
# ····
def check_mobile_view(request, mobile):
"""
校验手机号是否存在
url:/moblie/(?P<moblie>1[3-9]\d{9})/
:param request:
:param username:
:return:
"""
data = {
'mobile': mobile,
'count': User.objects.filter(mobile=mobile).count()
}
return json_response(data=data)
- verification/urls.py
from django.urls import path, re_path
from . import views
# url的命名空间
app_name = 'verification'
urlpatterns = [
path('image_code/', views.image_code_view, name='image_code'),
re_path('username/(?P<username>\w{5,20})/', views.check_username_view, name='check_username'),
re_path('mobile/(?P<mobile>1[3-9]\d{9})/', views.check_mobile_view, name='check_mobile'),
]
3. 前端js代码
register.html 将29行改成下面的内容
<input type="tel" placeholder="请输入手机号" name="mobile" class="form-control" autocomplete="off">
user/auth.js代码:
$(function () {
// 定义状态变量
//判断状态是false还是ture,如果是ture就直接引用
let isUsernameReady = false,
isPasswordReady = false,
isMobileReady = false,
isSmsCodeReady = false;
let $img = $('.form-contain .form-item .captcha-graph-img img');
// 1.点击刷新图像验证码
$img.click(function () {
$img.attr('src', '/image_code/?rand=' + Math.random())
});
// 2.鼠标离开用户名输入框校验用户名
let $username = $('#username'); //获取前端页面中的username框
$username.blur(fnCheckUsername); //blur是鼠标离开事件
//鼠标离开username触发函数fnCheckUsername
function fnCheckUsername() {
isUsernameReady = false; //校验用户名,没填入用户名为false
let sUsername = $username.val(); // 获取用户名字符串
if (sUsername === '') {
// 如果用户名为空,返回消息
message.showError('用户名不能为空')
return
}
if (!(/^\w{5,20}$/).test(sUsername)) {
//检测用户名长度
message.showError('请输入5-20个字符的用户名');
return
}
$.ajax({
url: '/username/' + sUsername + '/', //发送请求的地址
type: 'GET', //请求方式
dataType: 'json', //预期服务器返回的数据类型
success: function (data) {
// data 由服务器返回的数据,我们这里是json类型
if (data.data.data.count !== 0) {
//根据json的数据结构的到用户数量
message.showError(data.data.data.username + '已经注册,请重新输入!')
} else {
message.showInfo(data.data.username + '可以正常使用!');
isUsernameReady = true
}
},
error: function (xhr, msg) {
//请求失败时被调用的函数
message.showError('服务器超时,请重试!')
}
});
}
// 3.检测密码是否一致
let $passwordRepeat = $('input[name="password_repeat"]'); //获取前端input[name="password_repeat"] 中的内容(二次密码)
$passwordRepeat.blur(fnCheckPassword); //blur是鼠标离开事件
//鼠标离开username触发函数fnCheckPassword
function fnCheckPassword() {
isPasswordReady = false; //校验密码,没填入密码为false
let password = $('input[name="password"]').val(); // 获得密码字符串
let passwordRepeat = $passwordRepeat.val(); // 获取用户二次密码字符串
if (password === '' || passwordRepeat === '') {
message.showError('密码不能为空');
return
}
if (password !== passwordRepeat) {
message.showError('两次密码输入不一致');
return
}
if (password === passwordRepeat) {
isPasswordReady = true
}
}
// 4.检查手机号码是否可用
let $mobile = $('input[name="mobile"]'); //获取前端input[name="mobile"] 中的内容(手机密码)
$mobile.blur(fnCheckMobile);
//鼠标离开username触发函数fnCheckMobile
function fnCheckMobile () {
isMobileReady = true;
let sMobile = $mobile.val(); // 获得手机字符串
if(sMobile === ''){
message.showError('手机号码不能为空');
return
}
if(!(/^1[3-9]\d{9}$/).test(sMobile)){
message.showError('手机号码格式不正确');
return
}
$.ajax({
url: '/mobile/' + sMobile + '/',
type: 'GET',
dataType: 'json',
success: function (data) {
if(data.data.count !== 0){
message.showError(data.data.mobile + '已经注册,请重新输入!')
}else {
message.showInfo(data.data.mobile + '可以正常使用!');
isMobileReady = true
}
},
error: function (xhr, msg) {
message.showError('服务器超时,请重试!')
}
});
}
});