【Django开发】0到1开发美多shop项目:Celery短信和用户注册。全md文档笔记(附代码,已分享)

本系列文章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的配置信息

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

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

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

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

```python 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

json { "username": "itcast", "count": "1" }

|返回值|类型|是否必须|说明| |---|---|---|---| |username|str|是|用户名| |count|int|是|数量|

后端实现

在users/views.py中定义视图

```python

url(r'^usernames/(?P \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中修改

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

json { "mobile": "18512345678", "count": 0 }

|返回值|类型|是否必须|说明| |---|---|---|---| |mobile|str|是|手机号| |count|int|是|数量|

后端实现

在users/views.py中定义视图

```python

url(r'^mobiles/(?P 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中修改

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

json { "id": 9, "username": "python8", "mobile": "18512345678", }

|返回值|类型|是否必须|说明| |---|---|---|---| |id|int|是|用户id| |username|str|是|用户名| |mobile|str|是|手机号|

视图原型

```python

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)

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中定义视图

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

3. 前端编写

修改js/register.js

```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仓库获取完整文档和代码

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/404491.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode | 整数反转 C语言

Problem: 7. 整数反转 文章目录 思路解题方法Code结果 思路 运算部分 while(x > 0) {y x % 10;y * 10;x / 10; } y / 10;对于大于32位的数要用long int类型的变量保存用pow算-2的31次方和2的31次方-1。 解题方法 由思路得 Code int reverse(long int x){long int y …

LVGL:布局

一、Flex布局&#xff08;弹性布局&#xff09; 1.1、概述 Flex布局具备以下特点&#xff1a; 方向灵活&#xff1a;可以控制子元素沿水平方向&#xff08;row 默认&#xff09;或垂直方向&#xff08;column&#xff09;排列。自动填充&#xff1a;子元素可以按照比例分配空…

mysql-多表查询-内连接

一、简介 MySQL中的内连接&#xff08;INNER JOIN&#xff09;是一种多表查询的方式&#xff0c;它返回两个表中满足连接条件的记录。这意味着&#xff0c;只有当一个记录在两个表中都存在时&#xff0c;它才会出现在结果集中。 二、内连接查询语法 &#xff08;1&#xff0…

mybatis常用标签

一.定义sql语句 1.select 标签 属性介绍: &#xff08;1&#xff09;id :唯一的标识符. &#xff08;2&#xff09;parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User或user &#xff08;3&#xff09;resultType :语句返回值类型或别名。注意&#xff…

【Java面试】MQ(Message Queue)消息队列

目录 一、MQ介绍二、MQ的使用1应用解耦2异步处理3流量削峰4日志处理5消息通讯三、使用 MQ 的缺陷1.系统可用性降低:2.系统复杂性变高3.一致性问题四、常用的 MQActiveMQ:RabbitMQ:RocketMQ:Kafka:五、如何保证MQ的高可用?ActiveMQ:RabbitMQ:RocketMQ:Kafka:六、如何保…

transformer 最简单学习1 输入层embeddings layer,词向量的生成和位置编码

词向量的生成可以通过嵌入层&#xff08;Embedding Layer&#xff09;来完成。嵌入层是神经网络中的一种常用层&#xff0c;用于将离散的词索引转换为密集的词向量。以下是一个典型的步骤&#xff1a; 建立词表&#xff1a;首先&#xff0c;需要从训练数据中收集所有的词汇&…

uniapp实现全局悬浮框

uniapp实现全局悬浮框(按钮,页面,图片自行设置) 可拖动 话不多说直接上干货 1,在components新建组件(省去了每个页面都要引用组件的麻烦) 2,实现代码 <template><view class"call-plate" :style"top: top px;left: left px;" touchmove&quo…

ubuntu使用LLVM官方发布的tar.xz来安装Clang编译器

ubuntu系统上的软件相比CentOS更新还是比较快的&#xff0c;但是还是难免有一些软件更新得不那么快&#xff0c;比如LLVM Clang编译器&#xff0c;目前ubuntu 22.04版本最高还只能安装LLVM 15&#xff0c;而LLVM 18 rc版本都出来了。参见https://github.com/llvm/llvm-project/…

React 模态框的设计(三)拖动组件的完善

我在上次的Draggable组件的设计中给了一个简化的方法&#xff0c;今天我来完善一下这个组件&#xff0c;可用于任何可移动组件的包裹。完善后的效果如下所示&#xff1a; 这个优化中&#xff0c;增加了一个注目的效果&#xff0c;还增加了触发可拖动区域的指定功能&#xff0c;…

Sora - 探索AI视频模型的无限可能-官方报告解读与思考

一、引言 最近SORA火爆刷屏&#xff0c;我也忍不住找来官方报告分析了一下&#xff0c;本文将深入探讨OpenAI最新发布的Sora模型。Sora模型不仅仅是一个视频生成器&#xff0c;它代表了一种全新的数据驱动物理引擎&#xff0c;能够在虚拟世界中模拟现实世界的复杂现象。本文将重…

【更新】高考志愿填报系统功能更新啦

近期我们对金秋志愿高考志愿填报系统&#xff0c;进行了部分功能升级优化&#xff0c;让功能更符合用户的使用需求&#xff0c;大大提升用户体验感&#xff0c;快来了解一下金秋志愿的变化吧&#xff01; 一、新增测评管理-题目类型多样&#xff0c;支持单选和多选&#xff0c…

2024移动应用的发展趋势,开发者如何抢占变现先机?

2024年对移动应用市场将是变革之年&#xff0c;社交媒体变现方式的瞬息万变&#xff0c;到人工智能的快速崛起&#xff0c;移动应用市场的换代速度逐渐加快&#xff0c;一些新的机遇也在出现。 data.ai推出的2024全球移动市场预测&#xff1a; •TikTok将打破应用商店支出的所…

ShardingSphere5.x 分库分表

一、shardingSphere介绍 1、官网&#xff1a;Apache ShardingSphere 2、开发文档&#xff1a; 概览 :: ShardingSphere 3、shardingsphere-jdbc ShardingSphere-JDBC 定位为轻量级 Java 框架&#xff0c;在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库&#x…

【Linux系统化学习】深入理解匿名管道(pipe)和命名管道(fifo)

目录 进程间通信 进程间通信目的 进程间通信的方式 管道 System V IPC&#xff08;本地通信&#xff09; POSIX IPC&#xff08;网络通信&#xff09; 管道 什么是管道 匿名管道 匿名管道的创建 匿名管道的使用 匿名管道的四种情况 匿名管道的五种特性 命名管道 …

VSCODE上使用python_Django_创建最小项目

接上篇 https://blog.csdn.net/weixin_44741835/article/details/136135996?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22136135996%22%2C%22source%22%3A%22weixin_44741835%22%7D VSCODE官网&#xff1a; Editing Python …

无人机快递(物流)技术方案,无人机快递(物流)基础知识

无人机快递技术是一种利用无人机进行快递配送的先进技术。通过利用无人机&#xff0c;快递企业能够在偏远地区或难以通行的地区提供配送服务&#xff0c;同时提高配送效率并降低人力成本。 无人机基本情况 无人驾驶飞机简称“无人机”&#xff0c;是利用无线电遥控设备和自备的…

SQLite 的使用

SQLite 是一个轻量级、自包含和无服务器的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛应用于嵌入式系统、移动应用程序和小中型网站。它易于创建、需要的配置较少&#xff0c;并且提供了用于管理和操作数据的强大功能集。本文&#xff0c;我们将带领你…

linux---防火墙拓展

目录 一、iptables 1.基本语法 2.四表五链——重点记忆 2.1四表 2.2五链 2.3总结 3.iptables选项示例 3.1 -Z 清空流量计数 3.2 -P 修改默认规则 3.3 -D 删除规则 3.4 -R 指定编号替换规则 4.白名单 5.通用匹配 6.示例 6.1添加回环网卡 6.2可以访问端口 6.3 主…

Encoder-decoder 与Decoder-only 模型之间的使用区别

承接上文&#xff1a;Transformer Encoder-Decoer 结构回顾 笔者以huggingface T5 transformer 对encoder-decoder 模型进行了简单的回顾。 由于笔者最近使用decoder-only模型时发现&#xff0c;其使用细节和encoder-decoder有着非常大的区别&#xff1b;而huggingface的接口为…

设计模式——抽象工厂模式

定义: 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;提供一个创建一系列或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 概述:一个工厂可以提供创建多种相关产品的接口&#xff0c;而无需像工厂方法一样&#xff0c;为每一个产品都提供一个具体…