用户注册功能实现 四 (完)

用户注册功能实现 四 (完)

目的:

1、短信校验功能实现
2、注册功能实现功能实现(完)

接口校验功能:
前端通过 → js校验
后端接口views通过 → forms校验

应用技术:
1、前端:js(jQuery框架)、ajax(前后端交互)、(用户注册不使用submit提交)
2、后端:django接口设计(json),csrf防跨域攻击,form表单校验功能

一、注册功能

1.业务流程分析
  1. 判断用户名是否为空,是否已注册
  2. 判断密码是否为空,格式是否正确
  3. 判断两次密码是否一致
  4. 判断手机号码是否为空,格式是否正确
  5. 判断短信验证码是否为空,格式是否正确,是否与真实短信验证码相同
2.接口设计

接口说明:

类目说明
请求方法POST
url定义/user/register/(和前面页面get请求类似)
参数格式表单

注意:
1、这里我们发送的是ajax,而不是通过submit方式提交post请求。
2、post请求,前端请求要带上csrf token,注意csrf_token,虽然我们以前写了。

参数说明:

参数名类型是否必须描述
username字符串用户输入的用户名
password字符串用户输入的密码
password_repeat字符串用户输入的重复密码
mobile字符串用户输入的手机号码
sms_code字符串用户输入的短信验证码

注意:这里我们不需要图片验证码,因为当我们成功发送短信验证码后,这个参数就没用了。
返回结果:

{
    "errno": "0", 
 	"errmsg": "恭喜您,注册成功!", 
}
3.后端代码

constants代码

#保存设置常量
#图片验证码过期时间,单位秒
IMAGE_CODE_EXPIRES = 300

# 短信验证码长度
SMS_CODE_LENGTH = 4

# 短信验证码发送间隔 秒
SMS_CODE_INTERVAL = 60

# 短信验证码过期时间 分
SMS_CODE_EXPIRES = 5

# 短信发送模板
SMS_CODE_TEMP_ID = 1
  1. user/views.py代码:
from django.shortcuts import render
from django.views import View

from .forms import RegisterForm
from .models import User
from utils.json_res import json_response
from utils.res_code import Code, error_map


class RegisterView(View):

 	#注册页面的get请求
    def get(self, request):
        return render(request, 'user/register.html')
        
	#注册页面的post请求
    def post(self, request):
       #通过form表单自动校验
        form = RegisterForm(request.POST)
        #只有form校验成功才会执行。
        if form.is_valid():
        	#通过form的cleaned_data方法得到校验成功后的数据,而不是通过request.POST.get()方法获得。
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            mobile = form.cleaned_data.get('mobile')
            #create_user和create的区别:
           	#    create_user方法会把写入到数据库中的密码字段的数据自动加密,而create方法写入数据是明文。
            User.objects.create_user(username=username, password=password, mobile=mobile)
            return json_response(errmsg='恭喜你,注册成功!')
        else:
            # 定义一个错误信息列表
            err_msg_list = []
            for item in form.errors.values():
                err_msg_list.append(item[0])
            err_msg_str = '/'.join(err_msg_list)

            return json_response(errno=Code.PARAMERR, errmsg=err_msg_str)
  1. user/forms.py代码:
    在form的mobile字段我们使用到了以前的手机校验器
    在这里插入图片描述
import re

from django import forms
from django_redis import get_redis_connection

from .models import User
from verification.constants import SMS_CODE_LENGTH
#导入手机校验器
from verification.forms import mobile_validator

#用来校验表单数据的类
注意:
	1、类中规定的字段名,必须和前端html表单中要校验的字段名和js中校验的字段名三者统一,才会起作用。
	2、clean方法和clean_字段名:这两个方法胡区别是后者是用来校验单个具体字段,当某个字段有特殊需求时,推荐使用单个字段校验,前者可以校验所有字段,当要校验多个字段,后者两个或两个以上字段有关联时,比如(密码和重复密码,需要判断两个字段值是否相等时,推荐使用clean方法。)
class RegisterForm(forms.Form):
    username = forms.CharField(label='用户名', max_length=20, min_length=5,
                               error_messages={
                                   'max_length': '用户名长度要小于20',
                                   'min_length': '用户名长度要大于4',
                                   'required': '用户名不能为空'
                               })
    password = forms.CharField(label='密码', max_length=20, min_length=6,
                               error_messages={
                                   'max_length': '密码长度要小于20',
                                   'min_length': '密码长度要大于5',
                                   'required': '用户名不能为空'
                               })
    password_repeat = forms.CharField(label='确认密码', max_length=20, min_length=6,
                                      error_messages={
                                          'max_length': '密码长度要小于20',
                                          'min_length': '密码长度要大于5',
                                          'required': '用户名不能为空'
                                      })
    mobile = forms.CharField(label='手机号码', max_length=11, min_length=11,validators=[mobile_validator,], error_messages={
                                 'max_length': '手机号码长度有误',
                                 'min_length': '手机号码长度有误',
                                 'required': '手机号码不能为空'
                             })
    sms_code = forms.CharField(label='短信验证码', max_length=SMS_CODE_LENGTH, min_length=SMS_CODE_LENGTH,
                               error_messages={
                                   'max_length': '短信验证码长度有误',
                                   'min_length': '短信验证码长度有误长度有误',
                                   'required': '短信验证码不能为空'
                               })

    def clean_username(self):
        """
        校验用户名
        :return:username
        """
        username = self.cleaned_data.get('username')
        
        if User.objects.filter(username=username).exists():
            return forms.ValidationError('用户名已存在!')
        return username

    def clean_mobile(self):
        """
        校验手机号
        :return:mobile
        """
        mobile = self.cleaned_data.get('mobile')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            raise forms.ValidationError('手机号码格式不正确')

        if User.objects.filter(mobile=mobile).exists():
            raise forms.ValidationError('手机号码已注册!')

        return mobile

    def clean(self):
        """
        校验,密码,和短信验证码
        :return:
        """
        clean_data = super().clean()
        # 校验密码是否一致
        password = clean_data.get('password')
        password_repeat = clean_data.get('password_repeat')
        if password != password_repeat:
            raise forms.ValidationError('两次密码不一致!')

        # 校验短信验证码
        sms_code = clean_data.get('sms_code')
        moblie = clean_data.get('mobile')

        redis_conn = get_redis_connection(alias='verify_code')
        real_code = redis_conn.get('sms_text_{}'.format(moblie))
        if (not real_code) or (real_code.decode('utf-8') != sms_code):
            raise forms.ValidationError('短信验证码错误!')

`4.前端js代码(完整版)
user/register.is代码

$(() => {
    // 1、点击刷新图像验证码
    $('.captcha-graph-img img').click(function () {
        $(this).attr('src', '/image_code/?rand=' + Math.random())
    });
    //校验功能
    //定义一些状态变量
    let isUsernameReady = false,
        isPasswoedReady = false,
        isMobileReady = false,
        isSmsCodeReady = false;

    // 2.鼠标离开用户名输入框校验用户名
    let $username = $('#user_name');
    $username.blur(fnCheckUsername);

    function fnCheckUsername () {
        isUsernameReady = 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 + '/',  //例如 127.0.0.1:8000/username/zhangsan/ 发送请求
            type: 'GET',
            dataType: 'json',
            success: function (res) {
                if(res.data.count !== 0){
                    message.showError(res.data.username + '已经注册,请重新输入!')
                }else {
                    message.showInfo(res.data.username + '可以正常使用!')
                    isUsernameReady = true
                }
            },
            error: function (xhr, msg) {
                message.showError('服务器超时,请重试!')
            }
        });
    }

    // 3.检测密码是否一致
    let $passwordRepeat = $('input[name="password_repeat"]');
    $passwordRepeat.blur(fnCheckPassword);

    function fnCheckPassword () {
        isPasswordReady = 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"]');
    $mobile.blur(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('服务器超时,请重试!')
            }
        });

    }

    // 5.发送手机验证码
    let $smsButton = $('.sms-captcha');
    $smsButton.click(function () {
        let sCaptcha = $('input[name="captcha_graph"]').val();
        if(sCaptcha === ''){
            message.showError('请输入验证码');
            return
        }
        if(!isMobileReady){
            fnCheckMobile();
            return
        }

        $.ajax({
            url: '/sms_code/',
            type: 'POST',
            data: {
                mobile: $mobile.val(),
                captcha: sCaptcha
            },
            dataType: 'json',
            success: function (data) {
                if(data.errno !== '0'){
                    message.showError(data.errmsg)
                }else {
                    message.showSuccess(data.errmsg);
                    //设置禁用
                    $smsButton.attr('disabled',true);
                    //倒计时
                    var num = 60;
                    //设置计时器
                    let t = setInterval(function () {
                        $smsButton.html('倒计时'+num+'秒');
                        if(num === 1){
                            clearInterval(t);
                            $smsButton.removeAttr('disabled');
                            $smsButton.html('获取短信验证码');
                        }
                        num --;
                    },1000)
                }
            },
            error: function (xhr, msg) {
                message.showError('服务器超时,请重试!')
            }
        });

    });

    // 6.注册
    let $submitBtn = $('.register-btn');
    $submitBtn.click(function (e) {
        //阻止默认提交
        e.preventDefault();
        // 1.检查用户名
        if(!isUsernameReady){
            fnCheckUsername();
            return
        }
        // 2.检查密码
        if(!isPasswordReady){
            fnCheckPassword();
            return
        }
        // 3.检查电话号码
        if(!isMobileReady){
            fnCheckMobile();
            return
        }
        // 4.检查短信验证码
        let sSmsCode = $('input[name="sms_captcha"]').val();
        if(sSmsCode === ''){
            message.showError('短信验证码不能为空!');
            return
        }
        if(!(/^\d{4}$/).test(sSmsCode)){
            message.showError('短信验证码长度不正确,必须是4位数字!');
            return
        }
		//注意data中表单字段和后端form表单字段保持一致
        $.ajax({
            url: '/user/register/',
            type: 'POST',
            data:{
                username: $username.val(),
                password: $('input[name="password"]').val(),
                password_repeat: $passwordRepeat.val(),
                mobile: $mobile.val(),
                sms_code: sSmsCode
            },
            dataType: 'json',
            success: function (res) {
                if(res.errno === '0'){
                    message.showSuccess('恭喜您,注册成功!');
                    setTimeout(function () {
                        //注册成功后重定向到登录页面
                        window.location.href = '/user/login/'
                    }, 3000)
                }else{
                    //注册失败
                    message.showError(res.errmsg)
                }
            },
            error: function () {
                message.showError('服务器超时,请重试!')
            }
        })

    });
});

实现登录和注册页面的跳转
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值