开源web框架django知识总结(十九)
Posted 主打Python
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了开源web框架django知识总结(十九)相关的知识,希望对你有一定的参考价值。
开源web框架django知识总结(十九)
阿尔法商城(购物车)
购物车存储方案
新建apps->carts
- 必须是用户登录状态下,才可以保存购物车数据。
- 用户对购物车数据的操作包括:增、删、改、查、全选等等
- 每个用户的购物车数据都要做唯一性的标识。
1. 购物车存储方案
1.存储数据说明
- 如何描述一条完整的购物车记录?
- 用户,选择了两个 iPhone8 添加到了购物车中,状态为勾选
- 一条完整的购物车记录包括:
用户
、商品
、数量
、勾选状态
。 - 存储数据:user_id、sku_id、count、selected
2.存储位置说明
- 购物车数据量小,结构简单,更新频繁,所以我们选择内存型数据库Redis进行存储。
- 存储位置:dev.py文件中Redis数据库 5号库
"carts": # 购物车
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://192.168.42.128:6379/5",
"OPTIONS":
"CLIENT_CLASS": "django_redis.client.DefaultClient",
,
3.存储类型说明
- 提示:我们很难将用户、商品、数量、勾选状态存放到一条Redis记录中。所以我们要把购物车数据合理的分开存储。
- 用户、商品、数量:
hash
carts_user_id: sku_id1: count, sku_id3: count, sku_id5: count, ...
- 勾选状态:
set
- 只将已勾选商品的sku_id存储到set中,比如,1号和3号商品是被勾选的。
selected_user_id: [sku_id1, sku_id3, ...]
注释:Redis Smembers 命令返回集合中的所有的成员。 不存在的集合 key 被视为空集合。
4.存储逻辑说明
- 当要添加到购物车的商品已存在时,对商品数量进行累加计算。
- 当要添加到购物车的商品不存在时,向hash中新增field和value即可。
==============================================
购物车管理
添加购物车
提示:在商品详情页添加购物车使用局部刷新的效果。
1. 添加购物车接口设计和定义
1.请求方式
选项 | 方案 |
---|---|
请求方法 | post |
请求地址 | /carts/ |
2.请求参数:JSON
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
sku_id | int | 是 | 商品SKU编号 |
count | int | 是 | 商品数量 |
selected | bool | 否 | 是否勾选 |
3.响应结果:JSON
字段 | 说明 |
---|---|
code | 状态码 |
errmsg | 错误信息 |
2. 添加购物车后端逻辑实现
1.接收和校验参数 carts.views.py
import json
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views import View
from django_redis import get_redis_connection
from utils.views import login_required # 注意修改导包路径
from goods.models import SKU
# Create your views here.
class CartsView(View):
# 把sku商品加入购物车
@method_decorator(login_required)
def post(self, request):
# 1、提取参数
data = json.loads(request.body.decode())
sku_id = data.get('sku_id')
count = data.get('count')
selected = data.get('selected', True)
# 2、校验参数
if not all([sku_id, count]):
return JsonResponse('code': 400, 'errmsg': '缺少参数!')
if not isinstance(selected, bool):
return JsonResponse('code': 400, 'errmsg': '参数有误!')
# 3、判断是否登陆
user = request.user
if user.is_authenticated:
# 4、登陆写入redis
conn = get_redis_connection('carts')
# 4.1 记录sku商品数量——carts_<user_id> : sku_id: count
# conn.hmset('carts_%s'%user.id, sku_id:count) # 我们不能使用该函数,因为他会覆盖原有数据
conn.hincrby('carts_%s'%user.id, sku_id, amount=count) # 把sku商品数量增加count,如果不存在则新建
# 4.2 记录选中状态——selected_<user_id> : [sku_id]
if selected:
conn.sadd('selected_%s'%user.id, sku_id)
return JsonResponse('code': 0, 'errmsg': 'ok')
=========================================
展示购物车
1. 展示购物车接口设计和定义
1.请求方式
选项 | 方案 |
---|---|
请求方法 | GET |
请求地址 | /carts/ |
**2.请求参数:**无
3.响应结果:HTML cart.html
4.后端接口定义 carts.views.py
class CartsView(View):
def get(self, request):
# 0、初始化一个空字典,用于保存sku购物车数据,其格式和cookie购物车格式一样
cart_dict = # 1: count:xx, selected:xx
user = request.user
if user.is_authenticated:
# 1、用户登陆,则从redis中读取sku商品信息
pass
2. 展示购物车后端逻辑实现
1.查询Redis购物车
2.查询购物车SKU信息
3.返回响应数据
# 展示购物车
@method_decorator(login_required)
def get(self, request):
# 0、初始化一个空字典,用于保存sku购物车数据,其格式和cookie购物车格式一样
cart_dict = # 1: count:xx, selected:xx
user = request.user
if user.is_authenticated:
# 1、用户登陆,则从redis中读取sku商品信息
conn = get_redis_connection('carts')
# 2、sku商品数量、是否选中
# cart_redis_dict = b'1': b'8'
cart_redis_dict = conn.hgetall('carts_%s' % user.id)
# cart_redis_selected = [b'1']
cart_redis_selected = conn.smembers('selected_%s' % user.id) #smembers返回集合中的所有的成员。 不存在的集合 key 被视为空集合
#将cart_redis_dict与cart_redis_selected合并
for k, v in cart_redis_dict.items(): #字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。
# k: b'1'; v: b'8'
cart_dict[int(k)] =
'count': int(v),
'selected': k in cart_redis_selected # b'1' in [b'1']返回True
cart_skus = []
# 3、构建响应返回
for k, v in cart_dict.items():
# k: sku_id; v: count:xx, selected: xx
sku = SKU.objects.get(pk=k)
cart_skus.append(
'id': sku.id,
'name': sku.name,
'count': v['count'],
'selected': v['selected'],
'price': sku.price,
'default_image_url': sku.default_image_url.url,
'amount': sku.price * v['count']
)
return JsonResponse('code': 0, 'errmsg': 'ok', 'cart_skus': cart_skus)
==============================================
修改购物车
提示:在购物车页面修改购物车使用局部刷新的效果。
1. 修改购物车接口设计和定义
1.请求方式
选项 | 方案 |
---|---|
请求方法 | PUT |
请求地址 | /carts/ |
2.请求参数:JSON
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
sku_id | int | 是 | 商品SKU编号 |
count | int | 是 | 商品数量 |
selected | bool | 否 | 是否勾选 |
3.响应结果:JSON
字段 | 说明 |
---|---|
sku_id | 商品SKU编号 |
count | 商品数量 |
selected | 是否勾选 |
4.后端接口定义
# 修改购物车
def put(self, request):
user = request.user
if user.is_authenticated:
# 登陆,修改redis
pass
2. 修改购物车后端逻辑实现
1.接收和校验参数
2.修改Redis购物车
# 修改购物车
@method_decorator(login_required)
def put(self, request):
data = json.loads(request.body.decode())
sku_id = data.get('sku_id')
count = data.get('count')
selected = data.get('selected', True)
user = request.user
if user.is_authenticated:
# 登陆,修改redis
conn = get_redis_connection('carts')
conn.hmset('carts_%s' % user.id, sku_id: count) # 覆盖写入
if selected:
conn.sadd('selected_%s' % user.id, sku_id) #选中,sadd增加
else:
conn.srem('selected_%s' % user.id, sku_id) #未选中,srem删除
return JsonResponse(
'code': 0,
'errmsg': 'ok',
'cart_sku':
'id': sku_id,
'count': count,
'selected': selected
)
=======================================
删除购物车
提示:在购物车页面删除购物车使用局部刷新的效果。
1. 删除购物车接口设计和定义
1.请求方式
选项 | 方案 |
---|---|
请求方法 | DELETE |
请求地址 | /carts/ |
2.请求参数:JSON
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
sku_id | int | 是 | 商品SKU编号 |
3.响应结果:JSON
字段 | 说明 |
---|---|
code | 状态码 |
errmsg | 错误信息 |
4.后端接口定义
# 删除购物车
def delete(self, request):
user = request.user
# 1、已登陆
if user.is_authenticated:
pass
2. 删除购物车后端逻辑实现
1.接收和校验参数
2.删除Redis购物车
# 删除购物车
@method_decorator(login_required)
def delete(self, request):
# "sku_id": xxx
data = json.loads(
request.body.decode()
)
sku_id = data.get('sku_id')
user = request.user
# 已登陆
if user.is_authenticated:
conn = get_redis_connection('carts')
# 1.1 删除购物车哈希数据——carts_user_id : sku_id : count
# Hdel 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。
conn.hdel('carts_%s' % user.id, sku_id)
# 1.2 删除集合中的sku_id
# Srem 命令用于移除集合中的一个或多个成员元素,不存在的成员元素会被忽略。
#https://www.runoob.com/redis/redis-commands.html
conn.srem('selected_%s' % user.id, sku_id)
return JsonResponse('code': 0, 'errmsg': 'ok')
===========================================
全选购物车
提示:在购物车页面修改购物车使用局部刷新的效果。
1. 全选购物车接口设计和定义
1.请求方式
选项 | 方案 |
---|---|
请求方法 | PUT |
请求地址 | /carts/selection/ |
2.请求参数:JSON
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
selected | bool | 是 | 是否全选 |
3.响应结果:JSON
字段 | 说明 |
---|---|
code | 状态码 |
errmsg | 错误信息 |
4.后端接口定义
class CartSelectAllView(View):
# 设置全选/全取消
def put(self, request):
# 1、获取参数
if user.is_authenticated:
# 已登陆:把所有的sku_id加入/删除到selected_user_id的集合中
pass
2. 全选购物车后端逻辑实现
1.接收和校验参数
2.全选Redis购物车
class CartSelectAllView(View):
# 设置全选/全取消
@method_decorator(login_required)
def put(self, request):
# 1、获取参数
data = json.loads(request.body.decode())
selected = data.get("selected") # True or False
user = request.user
if user.is_authenticated:
# 已登陆:把所有的sku_id加入/删除到selected_user_id的集合中
conn = get_redis_connection('carts')
# 1、获取用户的购物车数据
# b'1': b'5'
cart_dict = conn.hgetall('carts_%s'%user.id)
# [b'1', b'2']
sku_ids = cart_dict.keys()
# 2、设置全/全取消
if selected:
conn.sadd('selected_%s'%user.id, *sku_ids)
else:
conn.srem('selected_%s'%user.id, *sku_ids)
return JsonResponse('code': 0, 'errmsg': 'ok')
=============================================
展示商品页面简单购物车
需求:用户鼠标悬停在商品页面右上角购物车标签上,以下拉框形式展示当前购物车数据。
1. 简单购物车数据接口设计和定义
1.请求方式
选项 | 方案 |
---|---|
请求方法 | GET |
请求地址 | /carts/simple/ |
**2.请求参数:**无
3.响应结果:JSON
字段 | 说明 |
---|---|
code | 状态码 |
errmsg | 错误信息 |
cart_skus[ ] | 简单购物车SKU列表 |
id | 购物车SKU编号 |
name | 购物车SKU名称 |
count | 购物车SKU数量 |
default_image_url | 购物车SKU图片 |
4.后端接口定义
class CartsSimpleView(View):
"""商品页面右上角购物车"""
def get(self, request):
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,查询Redis购物车
pass
# 构造简单购物车JSON数据
pass
2. 简单购物车数据后端逻辑实现
1.查询Redis购物车
2.构造简单购物车JSON数据
class CartsSimpleView(View):
def get(self, request):
# 读取购物车数据,把具体的sku商品信息返回
user = request.user
# 1: "count":xx, "selected":xxx
cart_dict = # 购物车数据——格式和cookie格式是一样的
if user.is_authenticated:
# 已登陆,从redis中读商品数据
conn = get_redis_connection('carts')
# b'1': b'4'
carts_redis = conn.hgetall('carts_%s'%user.id)
# [b'1']
carts_selected = conn.smembers('selected_%s'%user.id)
for k,v in carts_redis.items():
# k: b'1'; v: b'4'
cart_dict[int(k)] =
'count': int(v),
'selected': k in carts_selected
# 构造响应数据
cart_skus = []
for k,v in cart_dict.items():
# k: sku_id; v: "count":xx, "selected":xxx
sku = SKU.objects.get(pk=k)
cart_skus.append(
'id': sku.id,
'name': sku.name,
'count': v['count'],
'default_image_url': sku.default_image_url.url
)
return JsonResponse(
'code': 0,
'errmsg': 'ok',
'cart_skus': cart_skus
)
carts.urls.py
from django.urls import re_path
from .views import *
urlpatterns = [
re_path(r'^carts/$', CartsView.as_view()),
re_path(r'^carts/selection/$', CartSelectAllView.as_view()),
re_path(r'^carts/simple/$', CartsSimpleView.as_view()),
]
修改前端文件
1、1.html 修改动态加载“简单购物车”显示
<!-- <div class="guest_cart fr">
<a href="#" class="cart_name fl">我的购物车</a>
<div class="goods_count fl" id="show_count">15</div>
<ul class="cart_goods_show">
<li>
<img src="#" alt="商品图片">
<h4>商品名称手机</h4>
<div>4</div>
</li>
<li>
<img src="#" alt="商品图片">
<h4>商品名称手机</h4>
<div>5</div>
</li>
<li>
<img src="#" alt="商品图片">
<h4>商品名称手机</h4>
<div>6</div>
</li>
<li>
<img src="#" alt="商品图片">
<h4>商品名称手机</h4>
<div>6</div>
</li>
</ul>
</div> -->
<div class="guest_cart fr">
<a href="#" class="cart_name fl">我的购物车</a>
<div class="goods_count fl" id="show_count">[[ cart_total_count ]]</div>
<ul class="cart_goods_show">
<li v-for="sku in carts">
<img :src="sku.default_image_url" alt="商品图片">
<h4>[[ sku.name ]]</h4>
<div>[[ sku.count ]]</div>
</li>
</ul>
</div>
修改
- 为
-
2、修改detail.js
改19行
mounted: function()中添加:this.get_hot_goods();
把注释部分打开
var vm = new Vue( el: '#app', delimiters: ['[[', ']]'], data: host, username: '', //改 user_id: sessionStorage.user_id || localStorage.user_id, token: sessionStorage.token || localStorage.token, tab_content: detail: true, pack: false, comment: false, service: false , sku_id: '', sku_count: 1, sku_price: price, cart_total_count: 0, // 购物车总数量 carts: [], // 购物车数据 hot_skus: [], // 热销商品 cat: cat, // 商品类别 comments: [], // 评论信息 score_classes: 1: 'stars_one', 2: 'stars_two', 3: 'stars_three', 4: 'stars_four', 5: 'stars_five', , computed: sku_amount: function() return (this.sku_price * this.sku_count).toFixed(2); , mounted: function() // 获取cookie中的用户名 (增) this.username = getCookie('username'); // 添加用户浏览历史记录 this.get_sku_id(); axios.post(this.host+'/browse_histories/', sku_id: this.sku_id , responseType: 'json', withCredentials:true, ) .then(response=> console.log(response) ) .catch(error=> console.log(error) ) this.get_cart(); this.get_hot_goods(); this.get_comments(); , methods: // 退出登录按钮 logoutfunc: function () var url = this.host + '/logout/'; axios.delete(url, responseType: 'json', withCredentials:true, ) .then(response => location.href = 'http://192.168.42.128/login.html';//改退出页面404错误 ) .catch(error => console.log(error.response); ) , // 控制页面标签页展示 on_tab_content: function(name) this.tab_content = detail: false, pack: false, comment: false, service: false ; this.tab_content[name] = true; , // 从路径中提取sku_id get_sku_id: function() var re = /^\\/goods\\/(\\d+).html$/; this.sku_id = document.location.pathname.match(re)[1]; , // 减小数值 on_minus: function() if (this.sku_count > 1) this.sku_count--; , // 获取用户所有的资料 (增:校验用户是否登陆状态) get
以上是关于开源web框架django知识总结(十九)的主要内容,如果未能解决你的问题,请参考以下文章