【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 = Userfields = ('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 valuedef validate_allow(self, value):"""检验用户是否同意协议"""if value != 'true':raise serializers.ValidationError('请同意用户协议')return valuedef 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 datadef 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仓库获取完整文档和代码

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

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

消息队列MQ详解(Kafka、RabbitMQ、RocketMQ、ActiveMQ等)

文章目录 概述消息中间件的优势&#xff08;异步削峰解耦&#xff09;消息队列的缺点消息中间件模式分类消息队列使用场景和应用场景消息中间件常用协议消息中间件的组成如何实现高吞吐量MQ 如何避免消息堆积消息堆积如何处理如何解决消息队列的延时以及过期失效问题&#xff1…

电子元件分销商

Top 10 Active Electronic Parts Distributors List – 2022 / 2023 一家从众多制造商那里收购所有电子元件并销售给客户的公司被称为电子元件分销商。 A company that acquires all electronic components from numerous manufacturers and sells them to customers from a si…

【挖坑前后指针版】快速排序(3)

目录 挖坑版 整体思路 图解分析 代码实现 前后指针版 整体思路 图解分析 代码实现 在前面我们基于hoare的思想实现了hoare版本的快速排序&#xff0c;但是我们发现hoare版本的快排&#xff0c;易错点太多也不是那么容易理解&#xff0c;所以基于hoare的思想有创新了挖…

欢迎 Gemma: Google 最新推出开源大语言模型

今天&#xff0c;Google 发布了一系列最新的开放式大型语言模型 —— Gemma&#xff01;Google 正在加强其对开源人工智能的支持&#xff0c;我们也非常有幸能够帮助全力支持这次发布&#xff0c;并与 Hugging Face 生态完美集成。 Gemma 提供两种规模的模型&#xff1a;7B 参数…

Redis能保证数据不丢失吗?

引言 大家即使没用过Redis&#xff0c;也应该都听说过Redis的威名。 Redis是一种Nosql类型的数据存储&#xff0c;全称Remote Dictionary Server&#xff0c;也就是远程字典服务器&#xff0c;用过Dictionary的应该都知道它是一种键值对&#xff08;Key-Value&#xff09;的数…

网关服务gateway注册Consul时报错Consul service ids must not be empty

网关服务gateway启动时&#xff0c;初始化Consul相关配置时报错。 Consul service ids must not be empty, must start with a letter, end with a letter or digit, and have as interior characters only letters, digits, and hyphen: cbda-server-gateway:10.111.236.142:…

Unity 2021.3发布WebGL设置以及nginx的配置

使用unity2021.3发布webgl 使用Unity制作好项目之后建议进行代码清理&#xff0c;这样会即将不用的命名空间去除&#xff0c;不然一会在发布的时候有些命名空间webgl会报错。 平台转换 将平台设置为webgl 设置色彩空间压缩方式 Compression Format 设置为DisabledDecompre…

C语言特殊函数

静态函数 背景知识&#xff1a;普通函数都是跨文件可见的&#xff0c;即在文件 a.c 中定义的函数可以在 b.c 中使用。 静态函数&#xff1a;只能在定义的文件内可见的函数&#xff0c;称为静态函数。 语法 staitc void f(void) // 在函数头前面增加关键字 static &#xff…

Runaway Queries 管理:提升 TiDB 稳定性的智能引擎

在数字化系统扮演重要角色的今天&#xff0c;数据库稳定性成为企业关注的核心问题。对于重要计算机系统而言&#xff0c;突发的性能下降可能对业务造成不可估量的损失。为了稳定数据库性能&#xff0c;用户可以从管理流程入手规范变更的测试&#xff0c;或者利用产品手段减少预…

基于JAVA的房屋出售出租系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

SQL 中如何实现多表关联查询?

阅读本文之前请参阅----MySQL 数据库安装教程详解&#xff08;linux系统和windows系统&#xff09; 在SQL中&#xff0c;多表关联查询是通过使用JOIN操作来实现的&#xff0c;它允许你从两个或多个表中根据相关列的值来检索数据。以下是几种常见的JOIN类型&#xff1a; …

docker镜像和容器的关系

背景 镜像和容器都是docker中非常重要的概念&#xff0c;镜像是静态的&#xff0c;而容器是动态的&#xff0c;两者的关系就类似类和实例的关系&#xff0c;本文就来分析下两者的关联 镜像和容器 我们知道镜像是存放在仓库中的静态的文件&#xff0c;而容器是运行中的进程&a…

【Python_Zebra斑马打印机编程学习笔记(二)】基于BarTender将btw文件转换为zpl文件

基于BarTender将btw文件转换为zpl文件 基于BarTender将btw文件转换为zpl文件前言一、BarTender1、BarTender 介绍2、BarTender 安装 二、导出 ZPL 文件1、导出 ZPL 文件步骤2、Zebra 打印机驱动安装 基于BarTender将btw文件转换为zpl文件 前言 本文介绍如何基于 BarTender 软…

Android LinearLayout 如何让子元素靠下居中对齐 center bottom

Android LinearLayout 如何让子元素靠下居中对齐 center bottom 首先你需要知道两个知识点&#xff1a; android:layout_gravity 指定的是当前元素在父元素中的位置android: gravity 指定的是当前元素子元素的排布位置 比如&#xff1a; 有这么一个布局&#xff0c;我需要让…

TESTLINK 测试用例数据结构解析

一、node_types 测试组件信息表 我们查询表 select * from testlink.node_types; 得到如下结果 二、nodes_hierarchy 测试用例目录层次表 我们以下图的项目为例&#xff0c;来讲解 1、测试项目 首先&#xff0c;我们有个Train的项目&#xff0c;存在表testprojects中&#…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 2月24日,星期六

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年2月24日 星期六 农历正月十五 元宵节 1、 快递新规3月1日起施行&#xff0c;快递不得擅自放服务站&#xff0c;违者最高罚3万元。 2、 人社部&#xff1a;将外卖小哥、网约车司机等新就业形态劳动者纳入最低工资保障。 3…

防御保护--VPN

目录 VPN的概述 VPN的分类 VPN的核心技术 --- 隧道技术 VPN其他常用技术 VPN的概述 VPN --- 虚拟专用网 --- 一般指依靠ISP或者其他NSP&#xff0c;也可以是企业自身&#xff0c;提供的一条虚拟网 络专线。这个虚拟的专线是逻辑上的&#xff0c;而不是物理上的&#xff0c;所…

【深度学习】SSD 神经网络:彻底改变目标检测

一、说明 Single Shot MultiBox Detector &#xff08;SSD&#xff09; 是一项关键创新&#xff0c;尤其是在物体检测领域。在 SSD 出现之前&#xff0c;对象检测主要通过两阶段过程执行&#xff0c;首先识别感兴趣的区域&#xff0c;然后将这些区域分类为对象类别。这种方法虽…

C#,计算几何,计算机图形学(Computer Graphics)洪水填充算法(Flood Fill Algorithm)与源代码

1 泛洪填充算法(Flood Fill Algorithm) 泛洪填充算法(Flood Fill Algorithm) &#xff0c;又称洪水填充算法&#xff0c;是在很多图形绘制软件中常用的填充算法&#xff0c;最熟悉不过就是 windows 自带画图软件的油漆桶功能。 2 源程序 using System; using System.Collecti…

危险!Wyze 摄像头安全漏洞致1.3万用户隐私遭窥探

最近&#xff0c;一则关于 Wyze 摄像头再次出现安全漏洞的新闻引起了人们的广泛关注。据报道&#xff0c;该安全漏洞导致约1.3万用户的摄像头受到了未经授权的访问&#xff0c;使得这些用户的隐私信息遭到了窥视。这一事件再次引发了人们对网络安全的关注和讨论。 网络安全不仅…