用戶註冊功能

數據庫建立一條數據javascript

django操做數據庫模型html

1、用戶模型設計(用戶表的設計)java

  1.用戶表字段分析python

    用戶名(帳戶名)mysql

    密碼ajax

    手機redis

    郵箱sql

    郵箱是否有效數據庫

  2.用戶模型設計django

    開發效率極高,內置了不少功能,權限驗證,

    自定義User模型

    項目app/user/models.py

    建立

class UserManager(_UserManager):
"""
自定義管理器,用來修改使用create_superuser命令建立用戶必須使用email的行爲
"""
def create_superuser(self, username, password, email=None, **extra_fields):
super().create_superuser(username=username, password=password,
email=email, **extra_fields)
class User(AbstractUser):
"""
自定義的User模型,添加moblie, email_active字段
"""
mobile = models.CharField('手機號', max_length=11, unique=True,
help_text='手機號', error_messages={'unique': '此手機號碼已註冊'})

email_active = models.BooleanField('郵箱狀態', default=False)

class Meta:
db_table = 'tb_user' # 指定數據庫表名
verbose_name = '用戶' # 在admin站點中的顯示名稱
verbose_name_plural = verbose_name # 複數

def __str__(self):
return self.username

# 經過create_superuser 這個命令建立用戶時,須要的字段
REQUIRED_FIELDS = ['mobile']

# user模型至關強大,還有修改必須輸入email的這個行爲
# 管理器執行
objects = UserManager()

操做數據庫: 項目根目錄輸入命令:python manage.py makemigrations
      建立數據庫表格:python manage.py migrate
      進入數據庫:mysql -uroot -pqwe123
建立超級管理員:python manage.py createsuperuser

 

2、功能模型設計

1.接口設計思路

  1-1分析業務邏輯,明確在這個業務中須要涉及到幾個相關業務,將每一個子業務當作一個接口設計

  1-2分析接口的功能,明確接口的訪問方式和返回數據

    1-2-1接口的請求方式:GET PUT POST DELTE

    1-2-2接口的URL定義

    1-2-3須要接受什麼參數(路徑參數、查詢參數、表單,json)

    1-2-4返回的數據,及數據格式

2.註冊功能分析

  1,流程

  2,功能接口

    方式一次請求,就要作一次

  3,註冊頁面

  4,圖形驗證碼

  5,用戶名校驗是否註冊

  6,手機號碼校驗是否註冊

  7,短信驗證碼

  8,註冊保持用戶數據

 

三,註冊頁面

  1,接口設計

    1-1,接口說明

      條目          說明

      請求方式        GET

      url定義         '/user/regiseter'

      參數格式        無參數

    1-2返回數據

      註冊頁面html

    2.後端代碼

  

      2-1視圖

 

from django.shortcuts import render
from django.views import View

def login(requset):
return render(requset, 'user/login.html')


class RegisterView(View):
"""
註冊視圖
url:'/user/register'
"""
def get(self, request):
return render(request, 'user/register.html')

      2-2url

from django.urls import path
from . import views

app_name = 'user'

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

四,圖像驗證碼

  1.接口設計

  1-1接口說明

    條目          說明

    請求方法        GET

    url定義         /iamge_code 

    參數格式        查詢參數

  1.2參數說明

    參數名    類型    是否必須  描述

    rand     字符串    否    隨機浮點數字支付串

   1-3返回數據

    驗證碼圖片

 

驗證碼視圖

import logging

from django.shortcuts import render

from utils.captcha.captcha import captcha
from . import constants
from django.http import HttpResponse

#日誌器
logger =logging.getLogger('django')

def image_code_view(request):
"""
生成驗證碼
url:/image_code/
:param request:
:return:
"""
#1.生成一個驗證碼,隨機生成字符串,生成圖片
text, image = captcha.generate_captcha()
#2.在後端保持驗證碼,爲了等下它來校驗
#保存在session中
request.session['image_code'] = text
#給個過時時間
request.session.set_expiry(constants.IMAGE_CODE_EXPIRES)
#3.記錄一個日誌
logger.info('Imag code: {}'.format(text))
#4.返回驗證記錄
return HttpResponse(content=image, content_type='image/jpg')

五,用戶名校驗功能

  1.接口設計

  1-1接口說明

    條目          說明

    請求方法        GET

    url定義         /username/(?P<username>\w{5,20})/

    參數格式        url路徑參數

  1.2參數說明

    參數名      類型    是否必須  描述

    username     字符串    是    輸入用戶名

   1-3返回數據

    返回結果:

      {

      "errno": "0",

      "errmsg": "ok",

      "data": {

        "username": "username",    #查詢用戶名

        "count": 1           #用戶查詢數量

        }

      }

6、電話號碼校驗
  

  1.接口設計

  1-1接口說明

    條目          說明

    請求方法        GET

    url定義         /mobile/(?P<username>\1[3-9]\d{9})/

    參數格式        url路徑參數

  1.2參數說明

    參數名      類型    是否必須  描述

    mobile     字符串    是      輸入的手機號碼

   1-3返回數據

    返回結果:

      {

      "errno": "0",

      "errmsg": "ok",

      "data": {

        "username": "mobile",    #查詢手機號

        "count": 1           #手機號查詢數量

        }

      }

七,json響應數據結構設計
  目的:
    1,減小代碼坈餘,提升複用性,解耦
    2,分工協做

   1,結構設計

    {"errno": "0", "errmsg": "ok", "data": ""}

    字段    

 

 

 

目標utils創建文件res_code
from django.http import JsonResponse
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: "未知錯誤",
}
def json_response(errno=Code.OK, errmsg='', data=None, kwargs=None):

json_dict = {
'errno': errno,
'errmsg': errmsg,
'data': data
}
if kwargs and isinstance(kwargs, dict):
json_dict.update(kwargs)

return JsonResponse(json_dict)

8、獲取短信驗證碼

  1,業務流程分析
    校驗手機號嗎
    校驗圖像驗證碼
    校驗是否在60s內有發送記錄
    生成短信驗證碼
    發送短信
    保存這個短信驗證碼(保存在哪裏?)
    保存發送記錄

  2,接口設計
    2.1接口說明

      條目          說明

      請求方法        POST       #get查詢/獲取數據、post產生新數據

      url定義         /sms_code/

      參數格式        表單

    2.2參數說明

      參數名      類型    是否必須      描述

      mobile         字符串    是      輸入的手機號碼

      captcha     字符串    是      用戶輸入的圖像驗證碼

     2.3返回數據

      返回結果:

      {

      "errno": "0",

      "errmsg": "發送短信驗證碼成功",

      }

後端:
  1,校驗數據用form表單
  在verification目錄下新建 forms表單

verification/views.py文件代碼
  
class SmsCodeView(View):
"""
發送短信驗證碼
url: /sms_code/
"""

def post(self, request):
"""
     生成短信驗證碼
     發送短信
     保存這個短信驗證碼(保存在哪裏?)
     保存發送記錄
"""
form = CheckImageForm(request.POST, request=request)
        if form.is_valid():
#獲取手機號碼
mobile = form.cleaned_data.get('mobile')
#生成短信驗證碼
sms_code = ''.join([random.choice('0123456789') for _ in range(constants.SMS_CODE_LENGTH)])
#發送短信驗證碼 調用接口
logger.info('發送短信驗證碼[正常][mobile: %s sms_code: %s ]' % (mobile, sms_code))
#保持這個驗證碼 保持到redis
#5分鐘時效
#建立短信驗證碼發送記錄到key
sms_flag_key = 'sms_flag_{}'.format(mobile)
#建立短信驗證碼內容到key
sms_text_key = 'sms_text_{}'.format(mobile)
redis_conn = get_redis_connection(alias='verify_code')
pl = redis_conn.pipeline()

try:
pl.setex(sms_flag_key, constants.SMS_CODE_INTERVAL, 1)
pl.setex(sms_text_key,constants.IMAGE_CODE_EXPIRES*60, sms_code)
#讓管道通知redis執行命令
pl.execute()
return json_response(errmsg='短信驗證碼發送成功!')
except Exception as e:
logger.error('redis 執行異常: {}'.format(e))

return json_response(errno=Code.UNKOWNERR, errmsg=error_map[Code.UNKOWNERR])
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)
verification/forms.py文件代碼
  
from django import forms
from django.core.validators import RegexValidator
from django_redis import get_redis_connection

from user.models import User

#建立手機號碼正則校驗器
mobile_validator = RegexValidator(r'^1[3,9]\d{9}$', '手機號碼格式不正確')


class CheckImageForm(forms.Form):
"""
校驗手機號嗎
校驗圖像驗證碼
校驗是否在60s內有發送記錄
校驗圖形驗證碼
"""
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)

mobile = forms.CharField(max_length=11, min_length=11, validators=[mobile_validator], error_messages={
'max_length': '手機長度有誤!',
'min_length': '手機長度有誤!',
'required': '手機號碼不能爲空!',
})

captcha = forms.CharField(max_length=4, min_length=4, error_messages={
'max_length': '圖形驗證碼長度有誤!',
'min_length': '圖形驗證碼長度有誤!',
'required': '圖形驗證碼不能爲空!',
})

def clean(self):
clean_data = super().clean()
mobile = clean_data.get('mobile')
captcha = clean_data.get('captcha')
# 若是前面到校驗失敗,mobile captcha 是 none
# 若是前面到字段校驗有問題,就不須要往下進行了
if mobile and captcha:
#1,校驗圖形驗證碼
#獲取session中把保存到驗證碼,和用戶填入到進行比對
image_code = self.requset.session.get('image_code')
if not image_code:
raise forms.ValidationError('圖形驗證碼失效')
if image_code.upper() != captcha.upper():
raise forms.ValidationError('圖形驗證碼校驗失敗!')

#2,是否60秒之內發送太短信
#存在redis裏面
redis_conn = get_redis_connection(alias='verify_code')
if redis_conn.get('sms_flag_{}'.format(mobile)):
raise forms.ValidationError('獲取短信驗證碼過於頻繁')

#3,再次校驗手機號號碼是否註冊
if User.objects.filter(mobile=mobile).count():
raise forms.ValidationError('手機號碼已註冊,請從新輸入')
return clean_data

static/js/user/registe.js文件代碼
  
//5.發送短信驗證碼
let $smsButton = $('.sms-captcha');
$smsButton.click(()=>{
// 拿到數據
// 圖形驗證
let sCaptcha = $('input[name="captcha_graph"]').val();
if(sCaptcha === ''){
message.showError('請輸入圖形驗證碼!');
return
}
// 判斷手機號碼是否準備好
if(!isMolibleReady){
fnCheckMobile();
return
}

$
.ajax({
url: '/sms_code/',
type: 'POST',
data: {
mobile: $mobile.val(),
captcha: sCaptcha
},
dataType: 'json'
})
.done((res)=>{
if(res.errno !== '0'){
message.showError(res.errmsg)
}else {
message.showSuccess(res.errmsg)
}
})
.fail(()=>{
message.showError('服務器超時,請重試!')
});
})
static/js/base/common.js文件代碼
  
 function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// 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;
}

function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});


templates/user/registe.html文件代碼
{% 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">當即登陸 &gt;</a>
</div>
<form action="" method="post" class="form-contain">
{% csrf_token %}  #增長這個代碼
 
9、註冊功能
  1.業務流程分析
    1.1對參數進行校驗
      1.校驗用戶名
      2.校驗密碼
      3.校驗手機號碼
      4.校驗短信驗證碼

    1.2新建數據庫記錄
   
  2.接口設計  
    2.1接口說明

      條目          說明

      請求方法        POST       #get查詢/獲取數據、post產生新數據

      url定義         /user/register/

      參數格式        表單

    注意:post請求,必定要帶上csrf_token

    2.2參數說明

      參數名         類型    是否必須      描述

      username          字符串    是      用戶輸入到用戶名

      password      字符串    是      用戶輸入到密碼

      passwrod_repeat  字符串    是      用戶輸入到重複密碼

      mobile       字符串    是      用戶輸入到電話號碼

      sms_code      字符串    是      用戶輸入到短信驗證碼

     2.3返回數據

      返回結果:

      {

      "errno": "0",

      "errmsg": "恭喜您,註冊成功",

      }

user/views 代碼
  
class RegisterView(View):
"""
註冊視圖
url:'/user/register'
"""

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

def post(self, request):
# 1.校驗數據
form = RegisterForm(request.POST)
if form.is_valid():
# 2.建立數據
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
mobile = form.cleaned_data.get('mobile')
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)


user/forms代碼
from django import formsfrom django_redis import get_redis_connectionfrom verification import constantsfrom .models import Userfrom verification.forms import mobile_validatorclass RegisterForm(forms.Form):    """    用戶註冊表單    """    username = forms.CharField(label='用戶名', max_length=20, min_length=5,                               error_messages={                                   'max_length': "用戶名長度要小於20",                                   'min_length': "用戶名長度要大於5",                                   'required': "用戶名不能爲空",                               })    password = forms.CharField(label='密碼', max_length=20, min_length=6,                               error_messages={                                   'max_length': "密碼長度要小於20",                                   'min_length': "密碼長度要大於6",                                   'required': "密碼不能爲空",                               })    password_repeat = forms.CharField(label='密碼', max_length=20, min_length=5,                                      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=constants.SMS_CODE_LENGTH,                               min_length=constants.SMS_CODE_LENGTH,                               error_messages={                                   'max_length': "短信驗證碼長度不正確",                                   'min_length': "短信驗證碼長度不正確",                                   'required': "短信驗證碼不能爲空",                               })    def clean_username(self):        """        校驗用戶名        :return:        """        username = self.cleaned_data.get('username')        if User.objects.filter(username=username).exists():            raise forms.ValidationError('用戶名不存在')        return username    def clean_mobile(self):        """        單字段校驗,用clean_mobile        校驗手機號碼        :return:        """        mobile = self.cleaned_data.get('mobile')        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')        if password != password_repeat:            raise forms.ValidationError('兩次密碼不一致!')        #校驗短信驗證碼        sms_code = clean_data.get('sms_code')        mobile = clean_data.get('mobile')        redis_conn = get_redis_connection(alias='verify_code')        real_code = redis_conn.get('sms_text_{}'.format(mobile))        if (not real_code) or (real_code.decode('utf-8') != sms_code):            raise forms.ValidationError('短信驗證碼錯誤!')
相關文章
相關標籤/搜索