【Django开发】django美多商城项目完整开发4.0第4篇:用户部分,使用Celery完成发送短信【附代码文档】

举报
程序员一诺python 发表于 2025/07/15 21:23:12 2025/07/15
【摘要】 美多商城 商业模式介绍 1.B2B--企业对企业 2.C2C--个人对个人 5.O2O--线上到线下 开发流程 说明: 需求分析 1. 用户部分 注册 登录 个人信息 地址管理 修改密码 3. 购物车部分 购物车管理 项目架构 创建工程 1. 在git平台创建工程 2. 添加前端文件 合并 3. 创建Django REST framework工程 4. 修改manage.py

教程总体简介:美多商城、商业模式介绍、开发流程、需求分析、项目架构、创建工程、1. 在git平台创建工程、收货地址、省市区地址查询、使用缓存、用户地址管理、用户地址管理代码、用户部分、商品部分、数据库表设计、FastDFS分布式文件系统、Docker使用、Docker简介、安装与操作、使用Docker安装FastDFS、FastDFS客户端与自定义文件存储系统、CKEditor富文本编辑器、添加测试数据、页面静态化、定时任务、静态化首页的手动脚本、商品详情页、用户浏览历史记录、商品列表页、商品搜索、项目准备、配置、用户模型类、注册、购物车数据存储设计、添加到购物车、购物车部分、查询购物车数据、修改购物车数据、删除购物车数据、购物车全选、登录合并购物车、订单数据库设计、订单结算、订单部分、保存订单、下单成功页面、发起支付、保存支付结果、Xadmin、用户权限控制、数据库读写分离、MySQL主从同步、配置Django实现数据库读写分离、部署、图片验证码、短信验证码、跨域CORS、使用Celery完成发送短信、判断帐号是否存在、JWT、什么是JWT、Django REST framework JWT、登录、绑定用户身份接口、用户中心个人信息、邮件与验证、使用Django发送邮件、保存邮箱并发送验证邮件、验证邮箱链接

https://bbs.huaweicloud.com/blogs/453454

https://bbs.huaweicloud.com/blogs/455771


全套教程部分目录:

用户部分

使用Celery完成发送短信

meiduo/meiduo_mall下创建celery_tasks用于保存celery异步任务。

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

1
broker_url = "redis://127.0.0.1/14"

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

1
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文件,用于保存发送短信的异步任务

1
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异步任务发送短信

1
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

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

后端实现

在users/views.py中定义视图

1
# 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中修改

1
// 检查用户名
    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

1
{
    "mobile": "18512345678",
    "count": 0
}
返回值 类型 是否必须 说明
mobile str 手机号
count int 数量

后端实现

在users/views.py中定义视图

1
# 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中修改

1
// 检查手机号
    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

1
{
    "id": 9,
    "username": "python8",
    "mobile": "18512345678",
}
返回值 类型 是否必须 说明
id int 用户id
username str 用户名
mobile str 手机号

视图原型

1
# url(r'^users/$', views.UserView.as_view()),


class UserView(CreateAPIView):
    """
    用户注册
    传入参数:
        username, password, password2, sms_code, mobile, allow
    """
    pass

2. 后端实现

在users/serializers.py中创建序列化器对象 ```python 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)

1
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):
    """检验用户
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。