美多商城项目4.0文档完整教程(附代码资料)主要内容讲述:美多商城,项目准备1.B2B--企业对企业,2.C2C--个人对个人,3.B2C--企业对个人,4.C2B--个人对企业,5.O2O--线上到线下,6.F2C--工厂到个人。项目准备,配置1. 修改settings/dev.py 文件中的路径信息,2. INSTALLED_APPS,3. 数据库,4. Redis,5. 本地化语言与时区,6. 日志。用户部分,图片验证码。用户部分,使用Celery完成发送短信1. 判断用户名是否存在,2. 判断手机号是否存在:。用户部分,JWT起源,基于token的鉴权机制,JWT长什么样?,JWT的构成,总结,安装配置。用户部分,登录创建模型类,urllib使用说明。登录,登录回调处理创建模型类,urllib使用说明。登录,绑定用户身份接口创建模型类,urllib使用说明。邮件与验证,保存邮箱并发送验证邮件。收货地址,省市区地址查询。收货地址,使用缓存。商品部分,数据库表设计表结构,数据库模型类,1. 什么是FastDFS,2. 文件上传流程,3. 简易FastDFS构建。Docker使用,Docker简介1. 虚拟化,2. 什么是Docer,3. Docker组件,4 使用Docker做什么。Docker使用,安装与操作1. 在Ubuntu中安装Docker,2. 启动与停止,3. Docker镜像操作,4. Docker 容器操作,5. 将容器保存为镜像,6. 镜像备份与迁移。商品部分,FastDFS客户端与自定义文件存储系统1. FastDFS的Python客户端,2. 自定义Django文件存储系统,3. 在Django配置中设置自定义文件存储类,4. 添加image域名。商品部分,页面静态化。商品部分,商品详情页。商品部分,用户浏览历史记录1. 保存,2. 查看,获取商品列表数据。商品部分,商品搜索。购物车部分,购物车数据存储设计1. Redis保存已登录用户,2. Cookie保存未登录用户。购物车部分,查询购物车数据。购物车部分,登录合并购物车。订单部分,保存订单。支付,接入。Xadmin,用户权限控制1. 安装,2. 使用,1. 主从同步的定义,2. 主从同步的机制,3. 配置主从同步的基本步骤,4. 详细配置主从同步的方法。
全套笔记资料代码移步: 前往gitee仓库查看
感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~
全套教程部分目录:
部分文件图片:
用户部分
登录
1. 业务说明
验证用户名和密码,验证成功后,为用户签发JWT,前端将签发的JWT保存下来。
2. 后端接口设计
请求方式: POST /authorizations/
请求参数: JSON 或 表单
参数名 | 类型 | 是否必须 | 说明 |
---|---|---|---|
username | str | 是 | 用户名 |
password | str | 是 | 密码 |
返回数据: JSON
{"username": "python","user_id": 1,"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo5LCJ1c2VybmFtZSI6InB5dGhvbjgiLCJleHAiOjE1MjgxODI2MzQsImVtYWlsIjoiIn0.ejjVvEWxrBvbp18QIjQbL1TFE0c0ejQgizui_AROlAU"
}
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
username | str | 是 | 用户名 |
user_id | int | 是 | 用户id |
token | str | 是 | 身份认证凭据 |
3. 后端实现
Django REST framework JWT提供了登录签发JWT的视图,可以直接使用
from rest_framework_jwt.views import obtain_jwt_tokenurlpatterns = [url(r'^authorizations/$', obtain_jwt_token),
]
但是默认的返回值仅有token,我们还需在返回值中增加username和user_id。
通过修改该视图的返回值可以完成我们的需求。
在users/utils.py 中,创建
def jwt_response_payload_handler(token, user=None, request=None):"""自定义jwt认证成功返回数据"""return {'token': token,'user_id': user.id,'username': user.username}
修改配置文件
# JWTJWT_AUTH = {'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
}
4. 增加支持用户名与手机号均可作为登录账号
JWT扩展的登录视图,在收到用户名与密码时,也是调用Django的认证系统中提供的authenticate()来检查用户名与密码是否正确。
我们可以通过修改Django认证系统的认证后端(主要是authenticate方法)来支持登录账号既可以是用户名也可以是手机号。
修改Django认证系统的认证后端需要继承django.contrib.auth.backends.ModelBackend
,并重写authenticate方法。
authenticate(self, request, username=None, password=None, **kwargs)
方法的参数说明:
- request 本次认证的请求对象
- username 本次认证提供的用户账号
- password 本次认证提供的密码
我们想要让用户既可以以用户名登录,也可以以手机号登录,那么对于authenticate方法而言,username参数即表示用户名或者手机号。
重写authenticate方法的思路:
- 根据username参数查找用户User对象,username参数可能是用户名,也可能是手机号
- 若查找到User对象,调用User对象的check_password方法检查密码是否正确
在users/utils.py中编写:
def get_user_by_account(account):"""根据帐号获取user对象:param account: 账号,可以是用户名,也可以是手机号:return: User对象 或者 None"""try:if re.match('^1[3-9]\d{9}$', account):# 帐号为手机号user = User.objects.get(mobile=account)else:# 帐号为用户名user = User.objects.get(username=account)except User.DoesNotExist:return Noneelse:return userclass UsernameMobileAuthBackend(ModelBackend):"""自定义用户名或手机号认证"""def authenticate(self, request, username=None, password=None, **kwargs):user = get_user_by_account(username)if user is not None and user.check_password(password):return user
在配置文件中告知Django使用我们自定义的认证后端
AUTHENTICATION_BACKENDS = ['users.utils.UsernameMobileAuthBackend',
]
5. 前端代码
修改login.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
<html xmlns=" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"><title>美多商城-登录</title><link rel="stylesheet" type="text/css" href="css/reset.css"><link rel="stylesheet" type="text/css" href="css/main.css"><script type="text/javascript" src="js/host.js"></script><script type="text/javascript" src="js/vue-2.5.16.js"></script><script type="text/javascript" src="js/axios-0.18.0.min.js"></script>
</head>
<body><div class="login_top clearfix"><a href="index.html" class="login_logo"><img src="images/logo02.png"></a> </div><div class="login_form_bg" id='app'><div class="login_form_wrap clearfix"><div class="login_banner fl"></div><div class="slogan fl">商品美 · 种类多 · 欢迎光临</div><div class="login_form fr"><div class="login_title clearfix"><a href="javascript:;" class="cur">账户登录</a></div><div class="form_con"><div class="form_input cur"><form id="login-form" @submit.prevent="on_submit"><input type="text" v-model="username" @blur="check_username" name="" class="name_input" placeholder="请输入用户名或手机号"><div v-show="error_username" class="user_error" v-cloak>请填写用户名或手机号</div><input type="password" v-model="password" @blur="check_pwd" name="pwd" class="pass_input" placeholder="请输入密码"><div v-show="error_pwd" class="pwd_error" v-cloak>{{ error_pwd_message }}</div><div class="more_input clearfix"><input type="checkbox" v-model="remember"> <label>记住登录</label><a href="/find_password.html">忘记密码</a></div><input type="submit" name="" value="登 录" class="input_submit"></form></div></div><div class="third_party"><a @click="qq_login" class="qq_login"></a><a href="#" class="weixin_login">微信</a><a href="/register.html" class="register_btn">立即注册</a></div></div></div></div><div class="footer no-mp"><div class="foot_link"><a href="#">关于我们</a><span>|</span><a href="#">联系我们</a><span>|</span><a href="#">招聘人才</a><span>|</span><a href="#">友情链接</a> </div><p>CopyRight © 2016 北京美多商业股份有限公司 All Rights Reserved</p><p>电话:010-****888 京ICP备*******8号</p></div><script type="text/javascript" src="js/login.js"></script>
</body>
</html>
在js目录中新建login.js
var vm = new Vue({el: '#app',data: {host: host,error_username: false,error_pwd: false,error_pwd_message: '请填写密码',username: '',password: '',remember: false},methods: {// 获取url路径参数 get_query_string: function(name){ var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');var r = window.location.search.substr(1).match(reg);if (r != null) {return decodeURI(r[2]);}return null;},// 检查数据check_username: function(){if (!this.username) {this.error_username = true;} else {this.error_username = false;}},check_pwd: function(){if (!this.password) {this.error_pwd_message = '请填写密码';this.error_pwd = true;} else {this.error_pwd = false;}},// 表单提交on_submit: function(){this.check_username();this.check_pwd();if (this.error_username == false && this.error_pwd == false) {axios.post(this.host+'/authorizations/', {username: this.username,password: this.password}, {responseType: 'json',withCredentials: true}).then(response => {// 使用浏览器本地存储保存tokenif (this.remember) {// 记住登录sessionStorage.clear();localStorage.token = response.data.token;localStorage.user_id = response.data.user_id;localStorage.username = response.data.username;} else {// 未记住登录localStorage.clear();sessionStorage.token = response.data.token;sessionStorage.user_id = response.data.user_id;sessionStorage.username = response.data.username;}// 跳转页面var return_url = this.get_query_string('next');if (!return_url) {return_url = '/index.html';}location.href = return_url;}).catch(error => {if (error.response.status == 400) {this.error_pwd_message = '用户名或密码错误';} else {this.error_pwd_message = '服务器错误';}this.error_pwd = true;})}},// qq登录qq_login: function(){}}
});
登录
登录,亦即我们所说的第三方登录,是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录本项目。
若想实现登录,需要成为互联的开发者,审核通过才可实现。注册方法可参考链接[
成为互联开发者后,还需创建应用,即获取本项目对应与互联的应用ID,创建应用的方法参考链接[
登录开发文档连接[
使用登录的流程
创建模型类
创建一个新的应用oauth,用来实现第三方认证登录。总路由前缀 oauth/
在meiduo/meiduo_mall/utils/models.py
文件中创建模型类基类,用于增加数据新建时间和更新时间。
from django.db import modelsclass BaseModel(models.Model):"""为模型类补充字段"""create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")class Meta:abstract = True # 说明是抽象模型类, 用于继承使用,数据库迁移时不会创建BaseModel的表
在oauth/models.py中定义身份(openid)与用户模型类User的关联关系
from django.db import models
from meiduo_mall.utils.models import BaseModelclass OAuthUser(BaseModel):"""登录用户数据"""user = models.ForeignKey('users.User', on_delete=models.CASCADE, verbose_name='用户')openid = models.CharField(max_length=64, verbose_name='openid', db_index=True)class Meta:db_table = 'tb_oauth_qq'verbose_name = '登录用户数据'verbose_name_plural = verbose_name
进行数据库迁移
python manage.py makemigrations
python manage.py migrate
urllib使用说明
在后端接口中,我们需要向服务器发送请求,查询用户的信息,Python提供了标准模块urllib可以帮助我们发送http请求。
- urllib.parse.urlencode(query)
将query字典转换为url路径中的查询字符串
- urllib.parse.parse_qs(qs)
将qs查询字符串格式数据转换为python的字典
- urllib.request.urlopen(url, data=None)
发送http请求,如果data为None,发送GET请求,如果data不为None,发送POST请求
返回response响应对象,可以通过read()读取响应体数据,需要注意读取出的响应体数据为bytes类型
返回登录网址的视图
1. 后端接口设计:
请求方式: GET /oauth/qq/authorization/?next=xxx
请求参数: 查询字符串
参数名 | 类型 | 是否必须 | 说明 |
---|---|---|---|
next | str | 否 | 用户登录成功后进入美多商城的哪个网址 |
返回数据: JSON
{"login_url": "
}
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
login_url | str | 是 | qq登录网址 |
在配置文件中添加关于登录的应用开发信息
# 登录参数_CLIENT_ID = '101474184'
_CLIENT_SECRET = 'c6ce949e04e12ecc909ae6a8b09b637c'
_REDIRECT_URI = '
_STATE = '/'
新建oauth/utils.py文件,创建登录辅助工具类
from urllib.parse import urlencode, parse_qs
from urllib.request import urlopen
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadData
from django.conf import settings
import json
import loggingfrom . import constantslogger = logging.getLogger('django')class OAuth(object):"""认证辅助工具类"""def __init__(self, client_id=None, client_secret=None, redirect_uri=None, state=None):self.client_id = client_id or settings._CLIENT_IDself.client_secret = client_secret or settings._CLIENT_SECRETself.redirect_uri = redirect_uri or settings._REDIRECT_URIself.state = state or settings._STATE # 用于保存登录成功后的跳转页面路径def get_qq_login_url(self):"""获取qq登录的网址:return: url网址"""params = {'response_type': 'code','client_id': self.client_id,'redirect_uri': self.redirect_uri,'state': self.state,'scope': 'get_user_info',}url = ' + urlencode(params)return url
在oauth/views.py中实现视图
# url(r'^qq/authorization/$', views.AuthURLView.as_view()), class AuthURLView(APIView):"""获取登录的url"""def get(self, request):"""提供用于qq登录的url"""next = request.query_params.get('next')oauth = OAuth(state=next)login_url = oauth.get_qq_login_url()return Response({'login_url': login_url})
2. 前端
修改login.js,在methods中增加qq_login方法
// qq登录qq_login: function(){var next = this.get_query_string('next') || '/';axios.get(this.host + '/oauth/qq/authorization/?next=' + next, {responseType: 'json'}).then(response => {location.href = response.data.login_url;}).catch(error => {console.log(error.response.data);})}