【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://www.mzph.cn/news/698028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python网络爬虫实战:从入门到进阶

Python网络爬虫是一种自动化程序&#xff0c;用于从互联网上抓取、解析和提取数据。这种技术广泛应用于数据分析、机器学习、搜索引擎优化等领域。下面是一个Python网络爬虫的入门到进阶的实战指南&#xff1a; 入门篇 环境准备 安装Python和pip安装必要的库&#xff1a;reque…

突破编程_C++_高级教程(内存管理(1))

1 内存管理基础 C 的内存管理主要涉及如何分配、使用和释放计算机内存&#xff0c;以确保程序的正确运行和性能优化。其重要任务是避免内存泄漏和野指针等问题。 C 的内存管理是一个涉及多个方面和复杂概念的重要主题。正确地管理内存对于编写高效、稳定和安全的程序至关重要。…

网页403错误(Spring Security报异常 Encoded password does not look like BCrypt)

这个错误通常表现为"403 Forbidden"或"HTTP Status 403"&#xff0c;它指的是访问资源被服务器理解但拒绝授权。换句话说&#xff0c;服务器可以理解你请求看到的页面&#xff0c;但它拒绝给你权限。 也就是说很可能测试给定的参数有问题&#xff0c;后端…

学习Redis基础篇

1.初识Redis 1.认识NoSQL 2.认识Redis 3.连接redis命令 4.数据结构的介绍 5.通用命令 2.数据类型 1.String类型 常见命令&#xff1a;例子&#xff1a;set key value

Vue3实现页面顶部进度条

Vue3页面增加进度条 新建进度条组件新建bar.ts导航守卫中使用 Vue3项目使用导航守卫给页面增加进度条 新建进度条组件 loadingBar.vue <template><div class"wraps"><div ref"bar" class"bar"></div></div> <…

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;它们的风味和特点对啤酒的口感和品质产生着深远的影响。Fendi Club啤酒在麦芽与啤酒花的搭配方面有着与众不同的技巧和见解&#xff0c;让啤酒的口感更加丰富和迷人。 首先&#xff0c;麦芽的选择是啤酒酿造的关键之一。…

mysql之CRUD常见函数union查询

select select * from c insert 字段设置自增后&#xff0c;当我们指定增加一条数据后&#xff0c;往后增加的数据都会在该条数据后进行递增&#xff0c;但是可以认为的指定增加某条id不存在的数据 insert into c values(7,‘政治’) insert into c(c2) values(‘历史1’),(…

springboot解决@Autowired注入service时出现循环依赖问题

在Spring Boot开发过程中&#xff0c;Autowired注入Service时出现循环依赖是一个常见问题。循环依赖指的是两个或多个Bean相互依赖&#xff0c;形成闭环&#xff0c;导致Spring容器无法正常初始化这些Bean。这里提供几种解决Spring Boot中Autowired注入Service时循环依赖问题的…

掌握网络未来:深入解析RSVP协议及其在确保服务质量中的关键作用

第一部分&#xff1a;RSVP简介 资源预留协议&#xff08;RSVP&#xff09;是一种网络协议&#xff0c;用于在网络中的各个节点之间预留资源&#xff0c;以支持数据流的服务质量&#xff08;QoS&#xff09;要求。RSVP特别适用于需要固定带宽和处理延迟的应用&#xff0c;如视频…

基于AT89C51单片机与DS18B20的温度测量系统

摘 要:DALLAS 公司的单总线数字温度传感器DSl8B20 以其线路简单、硬件开销少、成本低廉等一系列优点,有着无可比拟的应用前景。文章首先介绍了DSl8B20 的特性及工作原理。接着提出了一种基于AT89C51 单片机与DS18B20 的温度测量报警系统,分析了系统的硬件结构及软件设计。其…

Vue3 父子组件传参

父子组件传值 1. 父组件给子组件传值 —— v-bind 传递字符串类型&#xff0c;不需要加 v-bind&#xff08;:&#xff09; 传递非字符串类型&#xff0c;需要加 v-bind&#xff08;:&#xff09; 2. 子组件接收父组件的传值 —— defineProps 3.子组件给父组件传参&#xf…

【目标检测新SOTA!v7 v4作者新作!】YOLO v9 思路复现 + 全流程优化

YOLO v9 思路复现 全流程优化 提出背景&#xff1a;深层网络的 信息丢失、梯度流偏差YOLO v9 设计逻辑可编程梯度信息&#xff08;PGI&#xff09;&#xff1a;使用PGI改善训练过程广义高效层聚合网络&#xff08;GELAN&#xff09;&#xff1a;使用GELAN改进架构 对比其他解法…

代码随想录算法训练营总结 | 慢慢总结,想起啥就先写上

二叉树总结 二叉树的结构 stauct TreeNode {int val&#xff1b;TreeNode* left;TreeNode* right; }二叉树的递归函数分析 二叉树的递归函数当做只有一个根节点&#xff0c;一个左子树&#xff0c;一个右节点的数去看&#xff0c;这看着是个废话&#xff0c; 其实很重要 回溯…

学习数据节构和算法的第13天

单链表 ​ 单链表是一种常见的数据结构&#xff0c;由一个个节点组成。 每个节点包含两个部分&#xff1a;数据部分和指针部分。 **数据部分&#xff1a;**存储节点中的具体数据。可以是任何类型的数据&#xff0c;如整数、浮点数、字符串等。 **指针部分&#xff1a;**指向…

FFMPEG 推流至 NGINX-RTMP 服务

NGINX 是一个非常出色的 HTTP 服务器&#xff0c;FFMPEG 是非常好的音视频框架。通过 NGINX 的 nginx-rtmp-module 模块结合在一起&#xff0c;实现一个流媒体服务器&#xff0c;它支持 RTMP 和 HLS&#xff08;Live Http Stream&#xff09;。 一、FFMPEG 文件推流&#xff1a…

精通Django模板(模板语法、继承、融合与Jinja2语法的应用指南)

模板&#xff1a; 基础知识&#xff1a; ​ 在Django框架中&#xff0c;模板是可以帮助开发者快速⽣成呈现给⽤户⻚⾯的⼯具模板的设计⽅式实现了我们MVT中VT的解耦(M: Model, V:View, T:Template)&#xff0c;VT有着N:M的关系&#xff0c;⼀个V可以调⽤任意T&#xff0c;⼀个…

百度地图海量点方案趟坑记录(百度地图GL版 + MapVGL + vue3 + ts)

核心需求描述 不同层级有不同的海量图标展示底层海量图标需要展示文字拖动、放大缩小都需要重新请求数据并展示固定地图中心点&#xff08;拖动、放大缩小&#xff0c;中心点始终在地图中心&#xff09; 示例图片&#xff1a;&#xff08;某些图片涉及公司数据&#xff0c;就未…

基础数据结构和算法《》

递归 1.递归应该一种比较常见的实现一些特殊代码逻辑时需要做的&#xff0c;但常常也是最绕的一种方式&#xff0c;在解释递归 之前&#xff0c;我们用循环和递归来做个比较1.1.如果你打开一扇门后&#xff0c;同样发现前方也有一扇们&#xff0c;紧接着你又打开下一扇门...直…

备战蓝桥杯---基础算法刷题1

最近在忙学校官网上的题&#xff0c;就借此记录分享一下有价值的题&#xff1a; 1.注意枚举角度 如果我们就对于不同的k常规的枚举&#xff0c;复杂度直接炸了。 于是我们考虑换一个角度&#xff0c;我们不妨从1开始枚举因子&#xff0c;我们记录下他的倍数的个数sum个&#…