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