django2.1.7从0开始搭建一个个人博客网站第8天

八、用户注册功能实现

1.分析

业务处理流程:

  • 判断用户名是否为空,是否已注册
  • 判断手机号是否为空,是否已注册
  • 判断密码是否为空,格式是否正确
  • 判断确认密码与密码是否相同
  • 判断短信验证码是否为空,是否格式正确,是否与真实的短信验证码相同

请求方法POST

url定义/user/register/

请求参数:url路径参数

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

注:由于是post请求,在向后端发起请求时,需要附带csrf token

1.前台代码实现

js

$(function () {
    let $username = $('#user_name'); //获取用户名
    let $img = $(".form-item .captcha-graph-img img");   // 获取图像
    let sImageCodeId = ""; //uuid
    let $mobile = $('#mobile');  // 选择id为mobile的网页元素,需要定义一个id为mobile手机号

     // 校验功能
    // 定义一些状态变量
    let isUsernameReady = false,
        isPasswordReady = false,
        isMobileReady = false;
        send_flag = true;    // 短信标记

    // let $imgCodeText = $('#input_captcha');
    // console.log(img);
    genreate();
    $img.click(genreate);
    function genreate() {
		sImageCodeId = generateUUID();
        let imageCodeUrl = '/image_code/' + sImageCodeId + '/';

        $img.attr('src', imageCodeUrl)
    }

     // 生成图片UUID验证码
    function generateUUID() {
    let d = new Date().getTime();
    if (window.performance && typeof window.performance.now === "function") {
        d += performance.now(); //use high-precision timer if available
    }
    let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        let r = (d + Math.random() * 16) % 16 | 0;
        d = Math.floor(d / 16);
        return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
    return uuid;
    }


    // 2、用户名验证逻辑
    // blur,触发失去焦点事件
    $username.blur(function () {
    fn_check_username();
    });

    // 判断用户名是否已经注册
    function fn_check_username() {
        // 校验用户名
        isUsernameReady = false;
    let sUsername = $username.val();  // 获取用户名字符串
    if (sUsername === "") {
      message.showError('用户名不能为空!');
      return
    }
    if (!(/^\w{5,20}$/).test(sUsername)) {
      message.showError('请输入5-20个字符的用户名');
      return
    }

    // 发送ajax请求,去后端查询用户名是否存在
    $.ajax({
      url: '/username/' + sUsername + '/',
      type: 'GET',
      dataType: 'json',
    })
      .done(function (res) {
        if (res.data.count === 1) {
          message.showError(res.data.username + '已注册,请重新输入!');
        } else {
          message.showSuccess(res.data.username + '能正常使用!');
          isUsernameReady = true
        }
      })
      .fail(function () {
        message.showError('服务器超时,请重试!');
      });
    }

    //3、手机号验证
    // 手机号校验,光标离开手机号输入框就校验
    $mobile.blur(fn_check_mobile);

    // 判断手机号是否注册
    function fn_check_mobile() {
        //检验手机号
        isMobileReady = false;
    let sMobile = $mobile.val();  // 获取用户输入的手机号码字符串
    if (sMobile === "") {
      message.showError('手机号不能为空!');
      return
    }
    if (!(/^1[345789]\d{9}$/).test(sMobile)) {
      message.showError('手机号码格式不正确,请重新输入!');
      return
    }

    $.ajax({
      url: '/mobiles/' + sMobile + '/',
      type: 'GET',
      dataType: 'json',
      async: false
    })
      .done(function (res) {
        if (res.data.count === 1) {
          message.showError(res.data.mobile + '已注册,请重新输入!');
        } else {
          message.showSuccess(res.data.mobile + '能正常使用!');
          isMobileReady = true;
        }
      })
      .fail(function () {
        message.showError('服务器超时,请重试!');
      });
    }

    // 4、发送短信验证码逻辑
    let $smsCodeBtn = $('.form-item .sms-captcha');  // 获取短信验证码按钮元素,需要定义一个id为input_smscode
    let $imgCodeText = $('#input_captcha');  // 获取用户输入的图片验证码元素,需要定义一个id为input_captcha

    $smsCodeBtn.click(function () {
    // 判断手机号是否输入
      if(send_flag){

          send_flag = false;
          // 判断手机号码是否准备好
        if(!isMobileReady){
            fn_check_mobile();
            return
        }
    // 13535353535
    // 判断用户是否输入图片验证码
    let text = $imgCodeText.val();  // 获取用户输入的图片验证码文本
    if (!text) {
        message.showError('请填写验证码!');
        return
    }

    if (!sImageCodeId) {
      message.showError('图片UUID为空');
      return
    }

    // 正常
    let SdataParams = {
      "mobile": $mobile.val(),   // 获取用户输入的手机号
      "text": text,   // 获取用户输入的图片验证码文本
      "image_code_id": sImageCodeId  // 获取图片UUID
    };
    // 向后端发送请求
    $.ajax({
      // 请求地址
      url: "/sms_code/",
      // 请求方式
      type: "POST",
      // 向后端发送csrf token
      headers: {
                // 根据后端开启的CSRFProtect保护,cookie字段名固定为X-CSRFToken
                "X-CSRFToken": getCookie("csrftoken")
      },

      data: JSON.stringify(SdataParams),
      // data: JSON.stringify(SdataParams),
      // 请求内容的数据类型(前端发给后端的格式)
      contentType: "application/json; charset=utf-8",
      // 响应数据的格式(后端返回给前端的格式)
      dataType: "json",
    })

      .done(function (res) {
          console.log(res);

        if (res.errno === "0") {
          // 倒计时60秒,60秒后允许用户再次点击发送短信验证码的按钮
           message.showSuccess('短信验证码发送成功');
          let num = 60;
          // 设置一个计时器
          let t = setInterval(function () {
            if (num === 1) {
              // 如果计时器到最后, 清除计时器对象
              clearInterval(t);
              // 将点击获取验证码的按钮展示的文本恢复成原始文本
              $smsCodeBtn.html("获取验证码");
              send_flag = true;
            } else {
              num -= 1;
              // 展示倒计时信息
              $smsCodeBtn.html(num + "秒");
            }
          }, 1000);
        }
        else {
          message.showError(res.errmsg);
          send_flag = true;
        }
      })

      .fail(function(){
        message.showError('服务器超时,请重试!');
      });
      }

    });




    // 5、注册逻辑
    let $register = $('.form-contain');  // 获取注册表单元素

    $register.submit(function (e) {
    // 阻止默认提交操作
    e.preventDefault();

    // 获取用户输入的内容
    let sUsername = $username.val();  // 获取用户输入的用户名字符串


    let sPassword = $("input[name=password]").val();


    let sPasswordRepeat = $("input[name=password_repeat]").val();


    let sMobile = $mobile.val();  // 获取用户输入的手机号码字符串
    let sSmsCode = $("input[name=sms_captcha]").val();

    // 判断用户名是否已注册
    if (!isUsernameReady) {
        fn_check_username();
      return
    }

    // 判断手机号是否为空,是否已注册
    if (!isMobileReady) {
        fn_check_mobile();
      return
    }


    // 判断用户输入的密码是否为空
    if ((!sPassword) || (!sPasswordRepeat)) {
      message.showError('密码或确认密码不能为空');
      return
    }

    // const reg = /^(?![^A-Za-z]+$)(?![^0-9]+$)[\x21-x7e]{6,18}$/
    // 以首字母开头,必须包含数字的6-18位
    // 判断用户输入的密码和确认密码长度是否为6-20位
      if (!(/^[0-9A-Za-z]{6,20}$/).test(sPassword)){
         message.showError('请输入6到20位密码');
          return
      }


    // 判断用户输入的密码和确认密码是否一致
    if (sPassword !== sPasswordRepeat) {
      message.showError('密码和确认密码不一致');
      return
    }



    // 判断用户输入的短信验证码是否为6位数字
    if (!(/^\d{6}$/).test(sSmsCode)) {
      message.showError('短信验证码格式不正确,必须为6位数字!');
      return
    }

    // 发起注册请求
    // 1、创建请求参数
    let SdataParams = {
      "username": sUsername,
      "password": sPassword,
      "password_repeat": sPasswordRepeat,
      "mobile": sMobile,
      "sms_code": sSmsCode
    };


    // 2、创建ajax请求
    $.ajax({
      // 请求地址
      url: "/user/register/",  // url尾部需要添加/
      // 请求方式
      type: "POST",
      data: JSON.stringify(SdataParams),
      headers: {
              // 根据后端开启的CSRFProtect保护,cookie字段名固定为X-CSRFToken
       "X-CSRFToken": getCookie("csrftoken")
       },
      // 请求内容的数据类型(前端发给后端的格式)
      contentType: "application/json; charset=utf-8",
      // 响应数据的格式(后端返回给前端的格式)
      dataType: "json",

    })
      .done(function (res) {
        if (res.errno === "0") {
          // 注册成功
          message.showSuccess('恭喜你,注册成功!');
           setTimeout(() => {
            // 注册成功之后重定向到主页
            window.location.href = '/user/login/';
          }, 1500)
        } else {
          // 注册失败,打印错误信息
          message.showError(res.errmsg);
        }
      })
      .fail(function(){
        message.showError('服务器超时,请重试!');
      });

    });




    // get cookie using jQuery
    function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      let cookies = document.cookie.split(';');
      for (let i = 0; i < cookies.length; i++) {
        let cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) === (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
    }



});




2.后端代码实现
views.py

# 在users目录下的views.py文件中定义如下类视图:
import json
import re

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseForbidden
from django.views import View
from django_redis import get_redis_connection
from django.contrib.auth import login

from dj_blog.utils.res_code import res_json
from users.models import User


class RegisterView(View):
    """
    username
    password
    password_ret
    mobile
    sms_code
    """

    def get(self, request):
        return render(request, 'users/register.html')

    def post(self, request):
        """
         "username": sUsername,
        "password": sPassword,
         "password_repeat": sPasswordRepeat,
         "mobile": sMobile,
         "sms_code": sSmsCode
        :param request:
        :return:
        """
        data_dict = request.body
        data_dict = json.loads(data_dict)

        username = data_dict.get('username')
        password = data_dict.get('password')
        password2 = data_dict.get('password_repeat')
        mobile = data_dict.get('mobile')
        sms_code = data_dict.get('sms_code')

        # 1.非空
        if not all([username, password, password2, mobile, sms_code]):
            return HttpResponseForbidden('填写数据不完整')
        # 2.用户名
        if not re.match('^[\u4e00-\u9fa5\w]{5,20}$', username):
            return HttpResponseForbidden('用户名为5-20个字符')
        if Users.objects.filter(username=username).count() > 0:
            return HttpResponseForbidden('用户名已经存在')
        # 密码
        if not re.match('^[0-9A-Za-z]{6,20}$', password):
            return HttpResponseForbidden('密码为6-20个字符')
        # 确认密码
        if password != password2:
            return HttpResponseForbidden('两个密码不一致')
        # 手机号
        if not re.match('^1[3456789]\d{9}$', mobile):
            return HttpResponseForbidden('手机号错误')
        if Users.objects.filter(mobile=mobile).count() > 0:
            return HttpResponseForbidden('手机号存在')
        # 短信验证码
        # 1.读取redis中的短信验证码
        redis_cli = get_redis_connection('verify_codes')
        sms_code_redis = redis_cli.get('sms_{}'.format(mobile))
        # 2.判断是否过期
        if sms_code_redis is None:
            return HttpResponseForbidden('短信验证码已经过期')
        # 3.删除短信验证码,不可以使用第二次
        redis_cli.delete('sms_' + mobile)
        redis_cli.delete('send_flag_' + mobile)
        # 4.判断是否正确
        if sms_code_redis.decode() != sms_code:
            return HttpResponseForbidden('短信验证码错误')
        # 处理
        # 1.创建用户对象
        user = Users.objects.create_user(
            username=username,
            password=password,
            mobile=mobile
        )
        # 2.状态保持
        login(request, user)
        # 向cookie中写用户名,用于客户端显示
        response = res_json(errmsg='恭喜你,注册成功!')
        return response

urls.py

from django.urls import path
from . import views

app_name = 'users'

urlpatterns = [
    path('register/',views.RegisterView.as_view(), name='register'),
]

总结:
1、使用AJAX提交表单,注册功能完成。
2、因为自定义的user是继承的django自带的用户类,所以可以使用它的create_user创建普通用户
3、使用内置auth认证系统进行登录login(request,user)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值