美多商城完整教程(附代码资料)主要内容讲述:欢迎来到美多商城!,项目准备。展示用户注册页面,创建用户模块子应用。用户注册业务实现,用户注册前端逻辑。图形验证码,图形验证码接口设计和定义。短信验证码,避免频繁发送短信验证码。账号登录,用户名登录。登录,登录开发文档。用户基本信息,查询并渲染用户基本信息。收货地址,省市区三级联动。收货地址,展示地址前后端逻辑。商品数据库表设计,SPU和SKU。准备商品数据,容器化方案Docker。首页广告,展示首页商品频道分类。商品列表页,列表页面包屑导航。商品搜索,Haystack扩展建立索引。商品详情页,统计分类商品访问量。购物车管理,添加购物车。购物车管理,删除购物车。订单,结算订单。提交订单,使用乐观锁并发下单。对接系统,订单支付功能。页面静态化,首页广告页面静态化。MySQL读写分离,MySQL主从同步。
全套笔记资料代码移步: 前往gitee仓库查看
感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~
全套教程部分目录:
部分文件图片:
登录
登录开发文档
登录:即我们所说的第三方登录,是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录本项目。
1. 互联开发者申请步骤
若想实现登录,需要成为互联的开发者,审核通过才可实现。
- 相关连接:[
2. 互联应用申请步骤
成为互联开发者后,还需创建应用,即获取本项目对应与互联的应用ID。
- 相关连接:[
3. 网站对接登录步骤
互联提供有开发文档,帮助开发者实现登录。
- 相关连接:[
4. 登录流程分析
5. 知识要点
- 当我们在对接第三方平台的接口时,一定要认真阅读第三方平台提供的文档。文档中一定会有接口的使用说明,方便我们开发。
定义登录模型类
登录成功后,我们需要将用户和美多商场用户关联到一起,方便下次登录时使用,所以我们选择使用MySQL数据库进行存储。
1. 定义模型类基类
为了给项目中模型类补充数据
创建时间
和更新时间
两个字段,我们需要定义模型类基类。 在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的表
2. 定义登录模型类
创建一个新的应用
oauth
,用来实现第三方认证登录。
# oauthurl(r'^oauth/', include('oauth.urls')),
在
oauth/models.py
中定义身份(openid)与用户模型类User的关联关系
from django.db import modelsfrom meiduo_mall.utils.models import BaseModel# Create your models here.sclass OAuthUser(BaseModel):"""登录用户数据"""user = models.ForeignKey('users.User', on_delete=models.CASCADE, verbose_name='用户')openid = models.C harField(max_length=64, verbose_name='openid', db_index=True)class Meta:db_table = 'tb_oauth_qq'verbose_name = '登录用户数据'verbose_name_plural = verbose_name
3. 迁移登录模型类
$ python manage.py makemigrations
$ python manage.py migrate
登录工具LoginTool
1. LoginTool介绍
- 该工具封装了登录时对接互联接口的请求操作。可用于快速实现登录。
2. LoginTool安装
pip install LoginTool
3. LoginTool使用说明
1.导入
from LoginTool.tool import OAuth
2.初始化
OAuth对象
oauth = OAuth(client_id=settings._CLIENT_ID, client_secret=settings._CLIENT_SECRET, redirect_uri=settings._REDIRECT_URI, state=next)
3.获取登录扫码页面,扫码后得到
Authorization Code
login_url = oauth.get_qq_url()
4.通过
Authorization Code
获取Access Token
access_token = oauth.get_access_token(code)
5.通过
Access Token
获取OpenID
openid = oauth.get_open_id(access_token)
OAuth2.0认证获取openid
待处理业务逻辑
# 提取code请求参数# 使用code向服务器请求access_token# 使用access_token向服务器请求openid# 使用openid查询该用户是否在美多商城中绑定过用户# 如果openid已绑定美多商城用户,直接生成JWT token,并返回# 如果openid没绑定美多商城用户,创建用户并绑定到openid
1. 获取登录扫码页面
1.请求方式
选项 | 方案 |
---|---|
请求方法 | GET |
请求地址 | /qq/login/ |
> | |
2.请求参数:查询参数 |
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
next | string | 否 | 用于记录登录成功后进入的网址 |
> | |||
3.响应结果:JSON |
字段 | 说明 |
---|---|
code | 状态码 |
errmsg | 错误信息 |
login_url | 登录扫码页面链接 |
> | |
4.后端逻辑实现 |
class AuthURLView(View):"""提供登录页面网址"""def get(self, request):# next表示从哪个页面进入到的登录页面,将来登录成功后,就自动回到那个页面next = request.GET.get('next')# 获取登录页面网址oauth = OAuth(client_id=settings._CLIENT_ID, client_secret=settings._CLIENT_SECRET, redirect_uri=settings._REDIRECT_URI, state=next)login_url = oauth.get_qq_url()return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'login_url':login_url})
5.登录参数
_CLIENT_ID = '101518219'
_CLIENT_SECRET = '418d84ebdc7241efb79536886ae95224'
_REDIRECT_URI = '
2. 接收Authorization Code
提示:
- 用户在登录成功后,会将用户重定向到我们配置的回调网址。
- 在重定向到回调网址时,会传给我们一个
Authorization Code
。 - 我们需要拿到
Authorization Code
并完成OAuth2.0认证获取openid。 -
在本项目中,我们申请登录开发资质时配置的回调网址为:
-
`
-
互联重定向的完整网址为:
-
`
class AuthUserView(View):"""用户扫码登录的回调处理"""def get(self, request):"""Oauth2.0认证"""# 接收Authorization Codecode = request.GET.get('code')if not code:return http.HttpResponseForbidden('缺少code')pass
url(r'^oauth_callback/$', views.AuthUserView.as_view()),
3. OAuth2.0认证获取openid
- 使用code向服务器请求access_token
- 使用access_token向服务器请求openid
class AuthUserView(View):"""用户扫码登录的回调处理"""def get(self, request):"""Oauth2.0认证"""# 提取code请求参数code = request.GET.get('code')if not code:return http.HttpResponseForbidden('缺少code')# 创建工具对象oauth = OAuth(client_id=settings._CLIENT_ID, client_secret=settings._CLIENT_SECRET, redirect_uri=settings._REDIRECT_URI)try:# 使用code向服务器请求access_tokenaccess_token = oauth.get_access_token(code)# 使用access_token向服务器请求openidopenid = oauth.get_open_id(access_token)except Exception as e:logger.error(e)return http.HttpResponseServerError('OAuth2.0认证失败')pass
4. 本机绑定www.meiduo.site域名
1.ubuntu系统或者Mac系统
编辑 /etc/hosts
2.Windows系统
编辑 C:\Windows\System32\drivers\etc\hosts
openid是否绑定用户的处理
1. 判断openid是否绑定过用户
使用openid查询该用户是否在美多商城中绑定过用户。
try:oauth_user = OAuthUser.objects.get(openid=openid)
except OAuthUser.DoesNotExist:# 如果openid没绑定美多商城用户pass
else:# 如果openid已绑定美多商城用户pass
2. openid已绑定用户的处理
如果openid已绑定美多商城用户,直接生成状态保持信息,登录成功,并重定向到首页。
try:oauth_user = OAuthUser.objects.get(openid=openid)
except OAuthUser.DoesNotExist:# 如果openid没绑定美多商城用户pass
else:# 如果openid已绑定美多商城用户# 实现状态保持qq_user = oauth_user.userlogin(request, qq_user)# 响应结果next = request.GET.get('state')response = redirect(next)# 登录时用户名写入到cookie,有效期15天response.set_cookie('username', qq_user.username, max_age=3600 * 24 * 15)return response
3. openid未绑定用户的处理
- 为了能够在后续的绑定用户操作中前端可以使用openid,在这里将openid签名后响应给前端。
- openid属于用户的隐私信息,所以需要将openid签名处理,避免暴露。
try:oauth_user = OAuthUser.objects.get(openid=openid)
except OAuthUser.DoesNotExist:# 如果openid没绑定美多商城用户access_token = generate_eccess_token(openid)context = {'access_token': access_token}return render(request, 'oauth_callback.html', context)
else:# 如果openid已绑定美多商城用户# 实现状态保持qq_user = oauth_user.userlogin(request, qq_user)# 重定向到主页response = redirect(reverse('contents:index'))# 登录时用户名写入到cookie,有效期15天response.set_cookie('username', qq_user.username, max_age=3600 * 24 * 15)return response
oauth_callback.html
中渲染access_token
<input v-model="access_token" type="hidden" name="access_token" value="{{ access_token }}">
4. 补充itsdangerous的使用
itsdangerous
模块的参考资料链接 [
-
安装:
pip install itsdangerous
-
TimedJSONWebSignatureSerializer
的使用 -
使用
TimedJSONWebSignatureSerializer
可以生成带有有效期的token
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from django.conf import settings# serializer = Serializer(秘钥, 有效期秒)serializer = Serializer(settings.SECRET_KEY, 300)# serializer.dumps(数据), 返回bytes类型token = serializer.dumps({'mobile': '18512345678'})
token = token.decode()# 检验token# 验证失败,会抛出itsdangerous.BadData异常serializer = Serializer(settings.SECRET_KEY, 300)
try:data = serializer.loads(token)
except BadData:return None
补充:openid签名处理
oauth.utils.py
def generate_eccess_token(openid):"""签名openid:param openid: 用户的openid:return: access_token"""serializer = Serializer(settings.SECRET_KEY, expires_in=constants.ACCESS_TOKEN_EXPIRES)data = {'openid': openid}token = serializer.dumps(data)return token.decode()
openid绑定用户实现
类似于用户注册的业务逻辑
-
当用户输入的手机号对应的用户已存在
-
直接将该已存在用户跟
openid
绑定 -
当用户输入的手机号对应的用户不存在
-
新建一个用户,并跟
openid
绑定
class AuthUserView(View):"""用户扫码登录的回调处理"""def get(self, request):"""Oauth2.0认证"""......def post(self, request):"""美多商城用户绑定到openid"""# 接收参数mobile = request.POST.get('mobile')pwd = request.POST.get('password')sms_code_client = request.POST.get('sms_code')access_token = request.POST.get('access_token')# 校验参数# 判断参数是否齐全if not all([mobile, pwd, sms_code_client]):return http.HttpResponseForbidden('缺少必传参数')# 判断手机号是否合法if not re.match(r'^1[3-9]\d{9}$', mobile):return http.HttpResponseForbidden('请输入正确的手机号码')# 判断密码是否合格if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):return http.HttpResponseForbidden('请输入8-20位的密码')# 判断短信验证码是否一致redis_conn = get_redis_connection('verify_code')sms_code_server = redis_conn.get('sms_%s' % mobile)if sms_code_server is None:return render(request, 'oauth_callback.html', {'sms_code_errmsg':'无效的短信验证码'})if sms_code_client != sms_code_server.decode():return render(request, 'oauth_callback.html', {'sms_code_errmsg': '输入短信验证码有误'})# 判断openid是否有效:错误提示放在sms_code_errmsg位置openid = check_access_token(access_token)if not openid:return render(request, 'oauth_callback.html', {'openid_errmsg': '无效的openid'})# 保存注册数据try:user = User.objects.get(mobile=mobile)except User.DoesNotExist:# 用户不存在,新建用户user = User.objects.create_user(username=mobile, password=pwd, mobile=mobile)else:# 如果用户存在,检查用户密码if not user.check_password(pwd):return render(request, 'oauth_callback.html', {'account_errmsg': '用户名或密码错误'})# 将用户绑定openidtry:OAuthUser.objects.create(openid=openid, user=user)except DatabaseError:return render(request, 'oauth_callback.html', {'qq_login_errmsg': '登录失败'})# 实现状态保持login(request, user)# 响应绑定结果next = request.GET.get('state')response = redirect(next)# 登录时用户名写入到cookie,有效期15天response.set_cookie('username', user.username, max_age=3600 * 24 * 15)return response
用户中心
用户基本信息
用户基本信息逻辑分析
1. 用户基本信息逻辑分析
以下是要实现的后端逻辑
- 用户模型补充
email_active
字段 - 查询并渲染用户基本信息
- 添加邮箱
- 发送邮箱验证邮件
-
验证邮箱
提示:
-
用户添加邮箱时,界面的局部刷新,我们选择使用
Vue.js
来实现。