數據庫建立一條數據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">當即登陸 ></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('短信驗證碼錯誤!')