【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)

【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第1张图片

本系列文章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 子模块

【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第2张图片

【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第3张图片

图形验证码

图形验证码接口设计和定义

1. 图形验证码接口设计

1.请求方式
选项 方案
请求方法 GET
请求地址 image_codes/(?P[\w-]+)/
2.请求参数:路径参数
参数名 类型 是否必传 说明
uuid string 唯一编号
3.响应结果:image/jpg

【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第4张图片

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[\w-]+)/$', views.ImageCodeView.as_view()),

图形验证码后端逻辑

1. 准备captcha扩展包

提示:captcha扩展包用于后端生成图形验证码

【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第5张图片

可能出现的错误
  • 报错原因:环境中没有Python处理图片的库:PIL

【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第6张图片

解决办法
  • 安装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
  • 图形验证码 请填写图形验证码
  • 3.图形验证码展示和存储效果

    2. Vue实现图形验证码校验

    1.register.html
  • 图形验证码 [[ error_image_code_message ]]
  • 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开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第7张图片

    短信验证码

    短信验证码逻辑分析

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第8张图片

    知识要点

    1. 保存短信验证码是为注册做准备的。
    2. 为了避免用户使用图形验证码恶意测试,后端提取了图形验证码后,立即删除图形验证码。
    3. Django不具备发送短信的功能,所以我们借助第三方的容联云通讯短信平台来帮助我们发送短信验证码。

    容联云通讯短信平台

    1. 容联云通讯短信平台介绍

    1.容联云官网

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第9张图片

    2.容联云管理控制台

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第10张图片

    3.容联云创建应用

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第11张图片

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第12张图片

    4.应用申请上线,并进行资质认证

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第13张图片

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第14张图片

    5.完成资质认证,应用成功上线

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第15张图片

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第16张图片

    6.添加测试号码

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第17张图片

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第18张图片

    7.短信模板

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第19张图片

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第20张图片

    2. 容联云通讯短信SDK测试

    1.模板短信SDK下载

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第21张图片

    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. 容联云通讯只是发送短信的平台之一,还有其他云平台可用,比如,阿里云等,实现套路都是相通的。
    2. 将发短信的类封装为单例,属于性能优化的一种方案。

    短信验证码后端逻辑

    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
  • [[ sms_code_tip ]] [[ error_sms_code_message ]]
  • 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.发送短信验证码效果展示

    【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)_第22张图片

    补充注册时短信验证逻辑

    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
  • [[ sms_code_tip ]] [[ error_sms_code_message ]] {% if sms_code_errmsg %} {{ sms_code_errmsg }} {% endif %}
  • 未完待续, 同学们请等待下一期

    全套笔记和代码自取移步gitee仓库: gitee仓库获取完整文档和代码

    感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

    你可能感兴趣的:(djangopython)