关于django:Django开发0到1开发美多shop项目Celery短信和用户注册全md文档笔记附代码已分享

7次阅读

共计 6712 个字符,预计需要花费 17 分钟才能阅读完成。

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

用户局部

应用 Celery 实现发送短信

meiduo/meiduo_mall 下创立 celery_tasks 用于保留 celery 异步工作。

在 celery_tasks 目录下创立 config.py 文件,用于保留 celery 的配置信息

broker_url = "redis://127.0.0.1/14"

在 celery_tasks 目录下创立 main.py 文件,用于作为 celery 的启动文件

from celery import Celery

  
  
# 为 celery 应用 django 配置文件进行设置
  
  
import os
if not os.getenv('DJANGO_SETTINGS_MODULE'):
    os.environ['DJANGO_SETTINGS_MODULE'] = 'meiduo_mall.settings.dev'

  
  
# 创立 celery 利用
  
  
app = Celery('meiduo')

  
  
# 导入 celery 配置
  
  
app.config_from_object('celery_tasks.config')

  
  
# 主动注册 celery 工作
  
  
app.autodiscover_tasks(['celery_tasks.sms'])

在 celery_tasks 目录下创立 sms 目录,用于搁置发送短信的异步工作相干代码。

将提供的发送短信的云通信 SDK 放到 celery_tasks/sms/ 目录下。

在 celery_tasks/sms/ 目录下创立 tasks.py 文件,用于保留发送短信的异步工作

import logging

from celery_tasks.main import app
from .yuntongxun.sms import CCP

logger = logging.getLogger("django")

  
  
# 验证码短信模板
  
  
SMS_CODE_TEMP_ID = 1

@app.task(name='send_sms_code')
def send_sms_code(mobile, code, expires):
    """
    发送短信验证码
    :param mobile: 手机号
    :param code: 验证码
    :param expires: 有效期
    :return: None
    """

    try:
        ccp = CCP()
        result = ccp.send_template_sms(mobile, [code, expires], SMS_CODE_TEMP_ID)
    except Exception as e:
        logger.error("发送验证码短信[异样][mobile: %s, message: %s]" % (mobile, e))
    else:
        if result == 0:
            logger.info("发送验证码短信[失常][mobile: %s]" % mobile)
        else:
            logger.warning("发送验证码短信[失败][mobile: %s]" % mobile)

在 verifications/views.py 中改写 SMSCodeView 视图,应用 celery 异步工作发送短信

from celery_tasks.sms import tasks as sms_tasks

class SMSCodeView(GenericAPIView):
    ...
        # 发送短信验证码
        sms_code_expires = str(constants.SMS_CODE_REDIS_EXPIRES // 60)
        sms_tasks.send_sms_code.delay(mobile, sms_code, sms_code_expires)

        return Response({"message": "OK"})

判断帐号是否存在

1. 判断用户名是否存在

后端接口设计:

申请形式:GET usernames/(?P<username>\w{5,20})/count/

申请参数:门路参数

参数 类型 是否必传 阐明
username str 用户名

返回数据:JSON

{
    "username": "itcast",
    "count": "1"
}
返回值 类型 是否必须 阐明
username str 用户名
count int 数量
后端实现

在 users/views.py 中定义视图

  
  
# url(r'^usernames/(?P<username>\w{5,20})/count/$', views.UsernameCountView.as_view()), 
  
  
class UsernameCountView(APIView):
    """用户名数量"""
    def get(self, request, username):
        """获取指定用户名数量"""
        count = User.objects.filter(username=username).count()

        data = {
            'username': username,
            'count': count
        }

        return Response(data)
前端实现

在 js/register.js 中批改

// 查看用户名
    check_username: function (){
            var len = this.username.length;
            if(len<5||len>20) {
                this.error_name_message = '请输出 5 -20 个字符的用户名';
                this.error_name = true;
            } else {this.error_name = false;}
            // 查看重名
            if (this.error_name == false) {
                axios.get(this.host + '/usernames/' + this.username + '/count/', {responseType: 'json'})
                    .then(response => {if (response.data.count > 0) {
                            this.error_name_message = '用户名已存在';
                            this.error_name = true;
                        } else {this.error_name = false;}
                    })
                    .catch(error => {console.log(error.response.data);
                    })
            }
        },

2. 判断手机号是否存在:

后端接口设计:

申请形式:GET mobiles/(?P<mobile>1[3-9]\d{9})/count

申请参数:门路参数

参数 类型 是否必须 阐明
mobile str 手机号

返回数据:JSON

{
    "mobile": "18512345678",
    "count": 0
}
返回值 类型 是否必须 阐明
mobile str 手机号
count int 数量
后端实现

在 users/views.py 中定义视图

  
  
# url(r'^mobiles/(?P<mobile>1[3-9]\d{9})/count/$', views.MobileCountView.as_view()),
  
  
class MobileCountView(APIView):
    """手机号数量"""
    def get(self, request, mobile):
        """获取指定手机号数量"""
        count = User.objects.filter(mobile=mobile).count()

        data = {
            'mobile': mobile,
            'count': count
        }

        return Response(data)
前端实现

在 js/register.js 中批改

// 查看手机号
    check_phone: function (){var re = /^1[345789]\d{9}$/;
            if(re.test(this.mobile)) {this.error_phone = false;} else {
                this.error_phone_message = '您输出的手机号格局不正确';
                this.error_phone = true;
            }
            if (this.error_phone == false) {
                axios.get(this.host + '/mobiles/'+ this.mobile + '/count/', {responseType: 'json'})
                    .then(response => {if (response.data.count > 0) {
                            this.error_phone_message = '手机号已存在';
                            this.error_phone = true;
                        } else {this.error_phone = false;}
                    })
                    .catch(error => {console.log(error.response.data);
                    })
            }
        },

注册

1. 后端接口设计:

申请形式:POST /users/

申请参数:JSON 或 表单

参数名 类型 是否必须 阐明
username str 用户名
password str 明码
password2 str 确认明码
sms_code str 短信验证码
mobile str 手机号
allow str 是否批准用户协定

返回数据:JSON

{
    "id": 9,
    "username": "python8",
    "mobile": "18512345678",
}
返回值 类型 是否必须 阐明
id int 用户 id
username str 用户名
mobile str 手机号
视图原型
  
  
# url(r'^users/$', views.UserView.as_view()),
  
  
class UserView(CreateAPIView):
    """
    用户注册
    传入参数:username, password, password2, sms_code, mobile, allow
    """
    pass

2. 后端实现

在 users/serializers.py 中创立序列化器对象

class CreateUserSerializer(serializers.ModelSerializer):
    """创立用户序列化器"""
    password2 = serializers.CharField(label='确认明码', write_only=True)
    sms_code = serializers.CharField(label='短信验证码', write_only=True)
    allow = serializers.CharField(label='批准协定', write_only=True)

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'password2', 'sms_code', 'mobile', 'allow')
        extra_kwargs = {
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅容许 5 -20 个字符的用户名',
                    'max_length': '仅容许 5 -20 个字符的用户名',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅容许 8 -20 个字符的明码',
                    'max_length': '仅容许 8 -20 个字符的明码',
                }
            }
        }

    def validate_mobile(self, value):
        """验证手机号"""
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格局谬误')
        return value

    def validate_allow(self, value):
        """测验用户是否批准协定"""
        if value != 'true':
            raise serializers.ValidationError('请批准用户协定')
        return value

    def validate(self, data):
        # 判断两次明码
        if data['password'] != data['password2']:
            raise serializers.ValidationError('两次明码不统一')

        # 判断短信验证码
        redis_conn = get_redis_connection('verify_codes')
        mobile = data['mobile']
        real_sms_code = redis_conn.get('sms_%s' % mobile)
        if real_sms_code is None:
            raise serializers.ValidationError('有效的短信验证码')
        if data['sms_code'] != real_sms_code.decode():
            raise serializers.ValidationError('短信验证码谬误')

        return data

    def create(self, validated_data):
        """创立用户"""
        # 移除数据库模型类中不存在的属性
        del validated_data['password2']
        del validated_data['sms_code']
        del validated_data['allow']
        user = super().create(validated_data)

        # 调用 django 的认证零碎加密明码
        user.set_password(validated_data['password'])
        user.save()

        return user

在 users/views.py 中定义视图

class UserView(CreateAPIView):
    """用户注册"""
    serializer_class = serializers.CreateUserSerializer

3. 前端编写

批改 js/register.js

// 注册
        on_submit: function(){this.check_username();
            this.check_pwd();
            this.check_cpwd();
            this.check_phone();
            this.check_sms_code();
            this.check_allow();

            if(this.error_name == false && this.error_password == false && this.error_check_password == false 
                && this.error_phone == false && this.error_sms_code == false && this.error_allow == false) {
                axios.post(this.host + '/users/', {
                        username: this.username,
                        password: this.password,
                        password2: this.password2,
                        mobile: this.mobile,
                        sms_code: this.sms_code,
                        allow: this.allow.toString()}, {responseType: 'json'})
                    .then(response => {location.href = '/index.html';})
                    .catch(error=> {if (error.response.status == 400) {if ('non_field_errors' in error.response.data) {this.error_sms_code_message = error.response.data.non_field_errors[0];
                            } else {this.error_sms_code_message = '数据有误';}
                            this.error_sms_code = true;
                        } else {console.log(error.response.data);
                        }
                    })
            }
        }

未完待续,同学们请期待下一期

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

感兴趣的小伙伴能够自取哦,欢送大家点赞转发~

正文完
 0