文章目录
购物车存储方案
- 分两种情况
用户登录
- 描述一条完整的购物车记录需要
- 用户、商品、数量、勾选状态
- 存储数据:user_id、sku_id、count、selected
- 存储位置:
- 选择redis数据库
- 数据存储类型
-
(1)选择hash类型,保存用户,商品,数量等信息。
存储的数据应为:carts_user_id: {sku_id1: count, sku_id3: count, sku_id5: count, …} -
(2)勾选状态:采用set类型存储
-
只将已勾选商品的sku_id存储到set中,比如,1号和3号商品是被勾选的
-
形式:selected_user_id: [sku_id1, sku_id3, …]
-
- 存储逻辑说明
- 当要添加到购物车的商品已存在时,对商品数量进行累加计算
- 当要添加到购物车的商品不存在时,向hash中新增field和value即可
用户未登录
存储数据
- 和上面是一样的user_id、sku_id、count、selected
存储位置
- 由于用户未登录,服务端无法拿到用户的ID
- 我们可以将未登录用户的购物车数据缓存到用户浏览器的cookie中,每个用户自己浏览器的cookie中存储属于自己的购物车数据
存储类型
- (1)浏览器的cookie中存储的数据类型是字符串
- (2)JSON字符串可以描述复杂结构的字符串数据,可以保证一条购物车记录不用分开存储
- 数据结构展示:
{
"sku_id1":{
"count":"1",
"selected":"True"
},
"sku_id3":{
"count":"3",
"selected":"True"
},
"sku_id5":{
"count":"3",
"selected":"False"
}
}
存储逻辑说明
- 当要添加到购物车的商品已存在时,对商品数量进行累加计算。
- 当要添加到购物车的商品不存在时,向JSON中新增field和value即可
数据安全处理:
- (1)浏览器cookie中存储的是字符串明文数据
- 我们需要对数据进行加密
- (2) 解决方案:pickle模块 和 base64模块
pickle模块介绍
- pickle模块是Python的标准模块,提供了对Python数据的序列化操作,可以将数据转换为bytes类型,且序列化速度快。
- 使用方法:
- pickle.dumps()将Python数据序列化为bytes类型数据
- pickle.loads()将bytes类型数据反序列化为python数据。
base64模块介绍
- 注意!!! : pickle模块序列化转换后的数据是bytes类型,浏览器cookie无法存储
- 介绍:
- base64模块是Python的标准模块,可以对bytes类型数据进行编码,并得到bytes类型的密文数据
- 使用:
- base64.b64encode()将bytes类型数据进行base64编码,返回编码后的bytes类型数据
- base64.b64deocde()将base64编码后的bytes类型数据进行解码,返回解码后的bytes类型数据。
下面是具体的代码实现
增加购物车
redis中
redis_conn = get_redis_connection('carts')
pl = redis_conn.pipeline()
# 新增购物车数据
pl.hincrby('carts_%s' % user.id, sku_id, count)
# 新增选中的状态
if selected:
pl.sadd('selected_%s' % user.id, sku_id)
# 执行管道
pl.execute()
cookie中
# 用户未登录,操作cookie购物车
cart_str = request.COOKIES.get('carts')
# 如果用户操作过cookie购物车
if cart_str:
# 将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典
cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
else: # 用户从没有操作过cookie购物车
cart_dict = {
}
# 判断要加入购物车的商品是否已经在购物车中,如有相同商品,累加求和,反之,直接赋值
if sku_id in cart_dict:
# 累加求和
origin_count = cart_dict[sku_id]['count']
count += origin_count
cart_dict[sku_id] = {
'count': count,
'selected': selected
}
# 将字典转成bytes,再将bytes转成base64的bytes,最后将bytes转字符串
cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
# 创建响应对象
response = http.JsonResponse({
'code': RETCODE.OK, 'errmsg': '添加购物车成功'})
# 响应结果并将购物车数据写入到cookie
response.set_cookie('carts', cookie_cart_str, max_age=constants.CARTS_COOKIE_EXPIRES)
删除购物车
redis中
redis_conn = get_redis_connection('carts')
pl = redis_conn.pipeline()
# 删除键,就等价于删除了整条记录
pl.hdel('carts_%s' % user.id, sku_id)
pl.srem('selected_%s' % user.id, sku_id)
pl.execute()
删除cookie购物车
cart_str = request.COOKIES.get('carts')
if cart_str:
# 将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典
cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
else:
cart_dict = {
}
# 创建响应对象
response = http.JsonResponse({
'code': RETCODE.OK, 'errmsg': '删除购物车成功'})
if sku_id in cart_dict:
del cart_dict[sku_id]
# 将字典转成bytes,再将bytes转成base64的bytes,最后将bytes转字符串
cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
# 响应结果并将购物车数据写入到cookie
response.set_cookie('carts', cookie_cart_str, max_age=constants.CARTS_COOKIE_EXPIRES)
return response
其余的修改,展示购物车都是类似的,这里就不说了
全选购物车
redis中:
# 用户已登录,操作redis购物车
redis_conn = get_redis_connection('carts')
cart = redis_conn.hgetall('carts_%s' % user.id)
sku_id_list = cart.keys()
if selected:
# 全选
redis_conn.sadd('selected_%s' % user.id, *sku_id_list)
else:
# 取消全选
redis_conn.srem('selected_%s' % user.id, *sku_id_list)
return http.JsonResponse({
'code': RETCODE.OK, 'errmsg': '全选购物车成功'})
cookie中
# 用户已登录,操作cookie购物车
cart = request.COOKIES.get('carts')
response = http.JsonResponse({
'code': RETCODE.OK, 'errmsg': '全选购物车成功'})
if cart is not None:
cart = pickle.loads(base64.b64decode(cart.encode()))
for sku_id in cart:
cart[sku_id]['selected'] = selected
cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
response.set_cookie('carts', cookie_cart, max_age=constants.CARTS_COOKIE_EXPIRES)
合并购物车
# 获取cookie中的购物车数据
cookie_cart_str = request.COOKIES.get('carts')
# cookie中没有数据就响应结果
if not cookie_cart_str:
return response
cookie_cart_dict = pickle.loads(base64.b64decode(cookie_cart_str.encode()))
new_cart_dict = {
}
new_cart_selected_add = []
new_cart_selected_remove = []
# 同步cookie中购物车数据
for sku_id, cookie_dict in cookie_cart_dict.items():
new_cart_dict[sku_id] = cookie_dict['count']
if cookie_dict['selected']:
new_cart_selected_add.append(sku_id)
else:
new_cart_selected_remove.append(sku_id)
# 将new_cart_dict写入到Redis数据库
redis_conn = get_redis_connection('carts')
pl = redis_conn.pipeline()
pl.hmset('carts_%s' % user.id, new_cart_dict)
# 将勾选状态同步到Redis数据库
if new_cart_selected_add:
pl.sadd('selected_%s' % user.id, *new_cart_selected_add)
if new_cart_selected_remove:
pl.srem('selected_%s' % user.id, *new_cart_selected_remove)
pl.execute()
# 清除cookie
response.delete_cookie('carts')
就到这里吧,全是增删改查,操作cookie和redis,其实很繁琐,但是不是很难,大家仔细看懂逻辑实现就可以。