本系列文章 md 笔记(已分享)次要探讨 django 商城我的项目相干常识。我的项目利用 Django 框架开发一套前后端不拆散的商城我的项目(4.0 版本)含代码和文档。性能包含前后端不拆散,不便 SEO。采纳 Django + Jinja2 模板引擎 + Vue.js 实现前后端逻辑,Nginx 服务器(反向代理)Nginx 服务器(动态首页、商品详情页、uwsgi 服务器(美多商场业务场景),后端服务:MySQL、Redis、Celery、RabbitMQ、Docker、FastDFS、Elasticsearch、Crontab,内部接口:容联云、QQ 互联、支付宝。
全套笔记和代码自取移步 gitee 仓库:gitee 仓库获取残缺文档和代码
感兴趣的小伙伴能够自取哦,欢送大家点赞转发~
共 11 章,132 子模块
图形验证码
图形验证码接口设计和定义
1. 图形验证码接口设计
1. 申请形式
选项 | 计划 |
---|---|
申请办法 | GET |
申请地址 | image_codes/(?P[\w-]+)/ |
2. 申请参数:门路参数
参数名 | 类型 | 是否必传 | 阐明 |
---|---|---|---|
uuid | string | 是 | 惟一编号 |
3. 响应后果:
image/jpg
2. 图形验证码接口定义
1. 图形验证码视图
class ImageCodeView(View):
"""图形验证码"""
def get(self, request, uuid):
"""
:param request: 申请对象
:param uuid: 惟一标识图形验证码所属于的用户
:return: image/jpg
"""
pass
2. 总路由
# verifications
url(r'^', include('verifications.urls')),
3. 子路由
# 图形验证码
url(r'^image_codes/(?P<uuid>[\w-]+)/$', views.ImageCodeView.as_view()),
图形验证码后端逻辑
1. 筹备 captcha 扩大包
提醒:
captcha
扩大包用于后端生成图形验证码
可能呈现的谬误
- 报错起因:环境中没有 Python 解决图片的库:PIL
解决办法
- 装置 Python 解决图片的库:
pip install Pillow
2. 筹备 Redis 数据库
筹备 Redis 的 2 号库存储验证码数据
"verify_code": { # 验证码
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2",
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",}
},
3. 图形验证码后端逻辑实现
class ImageCodeView(View):
"""图形验证码"""
def get(self, request, uuid):
"""
:param request: 申请对象
:param uuid: 惟一标识图形验证码所属于的用户
:return: image/jpg
"""
# 生成图片验证码
text, image = captcha.generate_captcha()
# 保留图片验证码
redis_conn = get_redis_connection('verify_code')
redis_conn.setex('img_%s' % uuid, constants.IMAGE_CODE_REDIS_EXPIRES, text)
# 响应图片验证码
return http.HttpResponse(image, content_type='image/jpg')
图形验证码前端逻辑
1. Vue 实现图形验证码展现
1.register.js
mounted(){
// 生成图形验证码
this.generate_image_code();},
methods: {
// 生成图形验证码
generate_image_code(){// 生成 UUID。generateUUID() : 封装在 common.js 文件中,须要提前引入
this.uuid = generateUUID();
// 拼接图形验证码申请地址
this.image_code_url = "/image_codes/" + this.uuid + "/";
},
......
}
2.register.html
<li>
<label> 图形验证码:</label>
<input type="text" name="image_code" id="pic_code" class="msg_input">
<img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code">
<span class="error_tip"> 请填写图形验证码 </span>
</li>
3. 图形验证码展现和存储成果
2. Vue 实现图形验证码校验
1.register.html
<li>
<label> 图形验证码:</label>
<input type="text" v-model="image_code" @blur="check_image_code" name="image_code" id="pic_code" class="msg_input">
<img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code">
<span class="error_tip" v-show="error_image_code">[[error_image_code_message]]</span>
</li>
2.register.js
check_image_code(){if(!this.image_code) {
this.error_image_code_message = '请填写图片验证码';
this.error_image_code = true;
} else {this.error_image_code = false;}
},
3. 图形验证码校验成果
短信验证码
短信验证码逻辑剖析
常识要点
- 保留短信验证码是为注册做筹备的。
- 为了防止用户应用图形验证码歹意测试,后端提取了图形验证码后,立刻删除图形验证码。
- Django 不具备发送短信的性能,所以咱们借助第三方的容联云通信短信平台来帮忙咱们发送短信验证码。
容联云通信短信平台
1. 容联云通信短信平台介绍
1. 容联云官网
- 容联云通信网址:https://www.yuntongxun.com/
- 注册并登陆
2. 容联云治理控制台
3. 容联云创立利用
4. 利用申请上线,并进行资质认证
5. 实现资质认证,利用胜利上线
6. 增加测试号码
7. 短信模板
2. 容联云通信短信 SDK 测试
1. 模板短信 SDK 下载
-
https://www.yuntongxun.com/doc/ready/demo/1_4_1_2.html
2. 模板短信 SDK 应用阐明
-
http://doc.yuntongxun.com/p/5a533e0c3b8496dd00dce08c
3. 集成模板短信 SDK
CCPRestSDK.py
:由容联云通信开发者编写的官网 SDK 文件,包含发送模板短信的办法ccp_sms.py
:调用发送模板短信的办法
4. 模板短信 SDK 测试
ccp_sms.py
文件中
# -*- coding:utf-8 -*-
from verifications.libs.yuntongxun.CCPRestSDK import REST
# 阐明:主账号,登陆云通信网站后,可在 "控制台 - 利用" 中看到开发者主账号 ACCOUNT SID
_accountSid = '8aaf070862181ad5016236f3bcc811d5'
# 阐明:主账号 Token,登陆云通信网站后,可在控制台 - 利用中看到开发者主账号 AUTH TOKEN
_accountToken = '4e831592bd464663b0de944df13f16ef'
# 请应用治理控制台首页的 APPID 或本人创立利用的 APPID
_appId = '8aaf070868747811016883f12ef3062c'
# 阐明:申请地址,生产环境配置成 app.cloopen.com
_serverIP = 'sandboxapp.cloopen.com'
# 阐明:申请端口,生产环境为 8883
_serverPort = "8883"
# 阐明:REST API 版本号放弃不变
_softVersion = '2013-12-26'
# 云通信官网提供的发送短信代码实例
# 发送模板短信
# @param to 手机号码
# @param datas 内容数据 格局为数组 例如:{'12','34'},如不需替换请填 ''
# @param $tempId 模板 Id
def sendTemplateSMS(to, datas, tempId):
# 初始化 REST SDK
rest = REST(_serverIP, _serverPort, _softVersion)
rest.setAccount(_accountSid, _accountToken)
rest.setAppId(_appId)
result = rest.sendTemplateSMS(to, datas, tempId)
print(result)
for k, v in result.items():
if k == 'templateSMS':
for k, s in v.items():
print('%s:%s' % (k, s))
else:
print('%s:%s' % (k, v))
if __name__ == '__main__':
# 留神:测试的短信模板编号为 1
sendTemplateSMS('17600992168', ['123456', 5], 1)
5. 模板短信 SDK 返回后果阐明
{
'statusCode': '000000', // 状态码。'000000' 示意胜利,反之,失败
'templateSMS':
{
'smsMessageSid': 'b5768b09e5bc4a369ed35c444c13a1eb', // 短信惟一标识符
'dateCreated': '20190125185207' // 短信发送工夫
}
}
3. 封装发送短信单例类
1. 封装发送短信单例类
class CCP(object):
"""发送短信的单例类"""
def __new__(cls, *args, **kwargs):
# 判断是否存在类属性_instance,_instance 是类 CCP 的惟一对象,即单例
if not hasattr(CCP, "_instance"):
cls._instance = super(CCP, cls).__new__(cls, *args, **kwargs)
cls._instance.rest = REST(_serverIP, _serverPort, _softVersion)
cls._instance.rest.setAccount(_accountSid, _accountToken)
cls._instance.rest.setAppId(_appId)
return cls._instance
2. 封装发送短信单例办法
def send_template_sms(self, to, datas, temp_id):
"""
发送模板短信单例办法
:param to: 注册手机号
:param datas: 模板短信内容数据,格局为列表,例如:['123456', 5],如不需替换请填 ''
:param temp_id: 模板编号,默认收费提供 id 为 1 的模板
:return: 发短信后果
"""
result = self.rest.sendTemplateSMS(to, datas, temp_id)
if result.get("statusCode") == "000000":
# 返回 0,示意发送短信胜利
return 0
else:
# 返回 -1,示意发送失败
return -1
3. 测试单例类发送模板短信后果
if __name__ == '__main__':
# 留神:测试的短信模板编号为 1
CCP().send_template_sms('17600992168', ['123456', 5], 1)
4. 常识要点
- 容联云通信只是发送短信的平台之一,还有其余云平台可用,比方,阿里云等,实现套路都是相通的。
- 将发短信的类封装为单例,属于性能优化的一种计划。
短信验证码后端逻辑
1. 短信验证码接口设计
1. 申请形式
选项 | 计划 |
---|---|
申请办法 | GET |
申请地址 | /sms_codes/(?P1[3-9]\d{9})/ |
2. 申请参数:门路参数和查问字符串
参数名 | 类型 | 是否必传 | 阐明 |
---|---|---|---|
mobile | string | 是 | 手机号 |
image_code | string | 是 | 图形验证码 |
uuid | string | 是 | 惟一编号 |
3. 响应后果:JSON
字段 | 阐明 |
---|---|
code | 状态码 |
errmsg | 错误信息 |
2. 短信验证码接口定义
class SMSCodeView(View):
"""短信验证码"""
def get(self, reqeust, mobile):
"""
:param reqeust: 申请对象
:param mobile: 手机号
:return: JSON
"""
pass
3. 短信验证码后端逻辑实现
class SMSCodeView(View):
"""短信验证码"""
def get(self, reqeust, mobile):
"""
:param reqeust: 申请对象
:param mobile: 手机号
:return: JSON
"""
# 接管参数
image_code_client = reqeust.GET.get('image_code')
uuid = reqeust.GET.get('uuid')
# 校验参数
if not all([image_code_client, uuid]):
return http.JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errmsg': '短少必传参数'})
# 创立连贯到 redis 的对象
redis_conn = get_redis_connection('verify_code')
# 提取图形验证码
image_code_server = redis_conn.get('img_%s' % uuid)
if image_code_server is None:
# 图形验证码过期或者不存在
return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图形验证码生效'})
# 删除图形验证码,防止歹意测试图形验证码
try:
redis_conn.delete('img_%s' % uuid)
except Exception as e:
logger.error(e)
# 比照图形验证码
image_code_server = image_code_server.decode() # bytes 转字符串
if image_code_client.lower() != image_code_server.lower(): # 转小写后比拟
return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '输出图形验证码有误'})
# 生成短信验证码:生成 6 位数验证码
sms_code = '%06d' % random.randint(0, 999999)
logger.info(sms_code)
# 保留短信验证码
redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
# 发送短信验证码
CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
# 响应后果
return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '发送短信胜利'})
短信验证码前端逻辑
1. Vue 绑定短信验证码界面
1.register.html
<li>
<label> 短信验证码:</label>
<input type="text" v-model="sms_code" @blur="check_sms_code" name="sms_code" id="msg_code" class="msg_input">
<a @click="send_sms_code" class="get_msg_code">[[sms_code_tip]]</a>
<span class="error_tip" v-show="error_sms_code">[[error_sms_code_message]]</span>
</li>
2.register.js
check_sms_code(){if(this.sms_code.length != 6){
this.error_sms_code_message = '请填写短信验证码';
this.error_sms_code = true;
} else {this.error_sms_code = false;}
},
2. axios 申请短信验证码
1. 发送短信验证码事件处理
send_sms_code(){
// 防止反复点击
if (this.sending_flag == true) {return;}
this.sending_flag = true;
// 校验参数
this.check_mobile();
this.check_image_code();
if (this.error_mobile == true || this.error_image_code == true) {
this.sending_flag = false;
return;
}
// 申请短信验证码
let url = '/sms_codes/' + this.mobile + '/?image_code=' + this.image_code+'&uuid='+ this.uuid;
axios.get(url, {responseType: 'json'})
.then(response => {if (response.data.code == '0') {
// 倒计时 60 秒
var num = 60;
var t = setInterval(() => {if (num == 1) {clearInterval(t);
this.sms_code_tip = '获取短信验证码';
this.sending_flag = false;
} else {
num -= 1;
// 展现倒计时信息
this.sms_code_tip = num + '秒';
}
}, 1000, 60)
} else {if (response.data.code == '4001') {
this.error_image_code_message = response.data.errmsg;
this.error_image_code = true;
} else { // 4002
this.error_sms_code_message = response.data.errmsg;
this.error_sms_code = true;
}
this.generate_image_code();
this.sending_flag = false;
}
})
.catch(error => {console.log(error.response);
this.sending_flag = false;
})
},
2. 发送短信验证码成果展现
补充注册时短信验证逻辑
1. 补充注册时短信验证后端逻辑
1. 接管短信验证码参数
sms_code_client = request.POST.get('sms_code')
2. 保留注册数据之前,比照短信验证码
redis_conn = get_redis_connection('verify_code')
sms_code_server = redis_conn.get('sms_%s' % mobile)
if sms_code_server is None:
return render(request, 'register.html', {'sms_code_errmsg':'有效的短信验证码'})
if sms_code_client != sms_code_server.decode():
return render(request, 'register.html', {'sms_code_errmsg': '输出短信验证码有误'})
2. 补充注册时短信验证前端逻辑
1.register.html
<li>
<label> 短信验证码:</label>
<input type="text" v-model="sms_code" @blur="check_sms_code" name="sms_code" id="msg_code" class="msg_input">
<a @click="send_sms_code" class="get_msg_code">[[sms_code_tip]]</a>
<span v-show="error_sms_code" class="error_tip">[[error_sms_code_message]]</span>
{% if sms_code_errmsg %}
<span class="error_tip">{{sms_code_errmsg}} </span>
{% endif %}
</li>