数据库创建一条数据
django操作数据库模型
一、用户模型设计(用户表的设计)
1.用户表字段分析
用户名(账户名)
密码
手机
邮箱
邮箱是否有效
2.用户模型设计
开发效率极高,内置了很多功能,权限验证,
自定义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
二、功能模型设计
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
参数格式 url路径参数
1.2参数说明
参数名 类型 是否必须 描述
username 字符串 是 输入用户名
1-3返回数据
返回结果:
{
"errno": "0",
"errmsg": "ok",
"data": {
"username": "username", #查询用户名
"count": 1 #用户查询数量
}
}
六、电话号码校验
1.接口设计
1-1接口说明
条目 说明
请求方法 GET
url定义 /mobile/(?P
参数格式 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)
八、获取短信验证码
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 %}
转载于:https://www.cnblogs.com/wdty/p/11305556.html