0
点赞
收藏
分享

微信扫一扫

美多商城项目之购物车存储方案、购物车管理、展示商品页面简单购物车


一、购物车存储方案

1.存储数据说明

  • 如何描述一条完整的购物车记录?
  • ​用户itcast,选择了两个 iPhone8 添加到了购物车中,状态为勾选​
  • 一条完整的购物车记录包括:​​用户​​​、​​商品​​​、​​数量​​​、​​勾选状态​​。
  • 存储数据: ​​user_id​​sku_id​​count​​selected​

2.存储位置说明

  • 购物车数据量小,结构简单,更新频繁,所以我们选择内存型数据库Redis进行存储。
  • 存储位置:​Redis数据库 4号库​

"carts": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/4",
"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, ...]​

美多商城项目之购物车存储方案、购物车管理、展示商品页面简单购物车_django_02

 

4.存储逻辑说明

  • 当要添加到购物车的商品已存在时,对商品数量进行累加计算。
  • 当要添加到购物车的商品不存在时,向hash中新增field和value即可。

2. 未登录用户购物车存储方案

1.存储数据说明

  • 存储数据:​user_id​​sku_id​​count​​selected​

2.存储位置说明

  • 由于用户未登录,服务端无法拿到用户的ID,所以服务端在生成购物车记录时很难唯一标识该记录。
  • 我们可以将未登录用户的购物车数据缓存到用户浏览器的​​cookie​​中,每个用户自己浏览器的cookie中存储属于自己的购物车数据。
  • 存储位置:​用户浏览器的cookie​

3.存储类型说明

  • 提示:浏览器的cookie中存储的数据类型是字符串。
  • 思考:如何在字符串中描述一条购物车记录?
  • 结论:JSON字符串可以描述复杂结构的字符串数据,可以保证一条购物车记录不用分开存储。

{
"sku_id1":{
"count":"1",
"selected":"True"
},
"sku_id3":{
"count":"3",
"selected":"True"
},
"sku_id5":{
"count":"3",
"selected":"False"
}
}

4.存储逻辑说明

  • 当要添加到购物车的商品已存在时,对商品数量进行累加计算。
  • 当要添加到购物车的商品不存在时,向JSON中新增field和value即可。

提示:

  • 浏览器cookie中存储的是字符串明文数据。
  • 我们需要对购物车这类隐私数据进行密文存储。
  • 解决方案:​​pickle模块​​​和​​base64模块​

5.pickle模块介绍

  • pickle模块是Python的标准模块,提供了对Python数据的序列化操作,可以将数据转换为bytes类型,且序列化速度快。
  • pickle模块使用:
  • ​pickle.dumps()​​将Python数据序列化为bytes类型数据。
  • ​pickle.loads()​​将bytes类型数据反序列化为python数据。

>>> import pickle

>>> dict = {'1': {'count': 10, 'selected': True}, '2': {'count': 20, 'selected': False}}
>>> ret = pickle.dumps(dict)
>>> ret
b'\x80\x03}q\x00(X\x01\x00\x00\x001q\x01}q\x02(X\x05\x00\x00\x00countq\x03K\nX\x08\x00\x00\x00selectedq\x04\x88uX\x01\x00\x00\x002q\x05}q\x06(h\x03K\x14h\x04\x89uu.'
>>> pickle.loads(ret)
{'1': {'count': 10, 'selected': True}, '2': {'count': 20, 'selected': False}}

6.base64模块介绍

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2^6=64,所以每6个比特位一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母​​A-Z​​​、​​a-z​​​、数字​​0-9​​,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。

  • 提示:pickle模块序列化转换后的数据是bytes类型,浏览器cookie无法存储。
  • base64模块是Python的标准模块,可以对bytes类型数据进行编码,并得到bytes类型的密文数据。
  • base64模块使用:
  • ​base64.b64encode()​​将bytes类型数据进行base64编码,返回编码后的bytes类型数据。
  • ​base64.b64deocde()​​将base64编码后的bytes类型数据进行解码,返回解码后的bytes类型数据。

>>> import base64
>>> ret
b'\x80\x03}q\x00(X\x01\x00\x00\x001q\x01}q\x02(X\x05\x00\x00\x00countq\x03K\nX\x08\x00\x00\x00selectedq\x04\x88uX\x01\x00\x00\x002q\x05}q\x06(h\x03K\x14h\x04\x89uu.'
>>> b = base64.b64encode(ret)
>>> b
b'gAN9cQAoWAEAAAAxcQF9cQIoWAUAAABjb3VudHEDSwpYCAAAAHNlbGVjdGVkcQSIdVgBAAAAMnEFfXEGKGgDSxRoBIl1dS4='
>>> base64.b64decode(b)
b'\x80\x03}q\x00(X\x01\x00\x00\x001q\x01}q\x02(X\x05\x00\x00\x00countq\x03K\nX\x08\x00\x00\x00selectedq\x04\x88uX\x01\x00\x00\x002q\x05}q\x06(h\x03K\x14h\x04\x89uu.'

美多商城项目之购物车存储方案、购物车管理、展示商品页面简单购物车_redis_03

二、购物车管理 

2.1 添加购物车

提示:在商品详情页添加购物车使用局部刷新的效果。

1. 添加购物车接口设计和定义

1.请求方式

选项

方案

请求方法

POST

请求地址

/carts/

2.请求参数:JSON

参数名

类型

是否必传

说明

sku_id

int


商品SKU编号

count

int


商品数量

selected

bool


是否勾选

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

4.后端接口定义

class CartsView(View):
"""购物车管理"""

def post(self, request):
"""添加购物车"""
# 接收和校验参数
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,操作redis购物车
pass
else:
# 用户未登录,操作cookie购物车
pass

定义路由

#工程路由为

urlpatterns = [
...
path('',include('apps.carts.urls')),

]
#子应用路由
from django.conf.urls import url
from apps.carts import views

urlpatterns = [
path('carts/',views.CartsView.as_view()),
]

2. 添加购物车后端逻辑实现

1.接收和校验参数

class CartsView(View):
"""购物车管理"""

def post(self, request):
"""添加购物车"""
# 接收参数
json_dict = json.loads(request.body.decode())
sku_id = json_dict.get('sku_id')
count = json_dict.get('count')
selected = json_dict.get('selected', True)

# 判断参数是否齐全
if not all([sku_id, count]):
return http.HttpResponseBadRequest('缺少必传参数')
# 判断sku_id是否存在
try:
SKU.objects.get(id=sku_id)
except SKU.DoesNotExist:
return http.HttpResponseBadRequest('商品不存在')
# 判断count是否为数字
try:
count = int(count)
except Exception:
return http.HttpResponseBadRequest('参数count有误')
# 判断selected是否为bool值
if selected:
if not isinstance(selected, bool):
return http.HttpResponseBadRequest('参数selected有误')

# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,操作redis购物车
pass
else:
# 用户未登录,操作cookie购物车
pass

2.添加购物车到Redis

class CartsView(View):
"""购物车管理"""

def post(self, request):
"""添加购物车"""
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,操作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()
# 响应结果
return http.JsonResponse({'code': 0, 'errmsg': '添加购物车成功'})
else:
# 用户未登录,操作cookie购物车
pass

3.添加购物车到cookie

class CartsView(View):
"""购物车管理"""

def post(self, request):
"""添加购物车"""
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,操作redis购物车
......
else:
# 用户未登录,操作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': 0, 'errmsg': '添加购物车成功'})
# 响应结果并将购物车数据写入到cookie
response.set_cookie('carts', cookie_cart_str, max_age=7*24*3600)
return response

2.2 展示购物车

1. 展示购物车接口设计和定义

1.请求方式

选项

方案

请求方法

GET

请求地址

/carts/

2.请求参数:

3.响应结果:JSON

{
"code": 0,
"errmsg": "OK",
"cart_skus": [
{
"id": 1,
"name": "Apple MacBook Pro 13.3英寸笔记本 银色",
"count": 1,
"selected": "True",
"default_image_url": "http://192.168.19.128:8888/group1/M00/00/02/CtM3BVrPB4GAWkTlAAGuN6wB9fU4220429",
"price": "11388.00",
"amount": "11388.00"
}
]
}

4.后端接口定义

class CartsView(View):
"""购物车管理"""

def get(self, request):
"""展示购物车"""
user = request.user
if user.is_authenticated:
# 用户已登录,查询redis购物车
pass
else:
# 用户未登录,查询cookies购物车
pass

2. 展示购物车后端逻辑实现

1.查询Redis购物车

class CartsView(View):
"""购物车管理"""

def get(self, request):
"""展示购物车"""
user = request.user
if user.is_authenticated:
# 用户已登录,查询redis购物车
redis_conn = get_redis_connection('carts')
# 获取redis中的购物车数据
redis_cart = redis_conn.hgetall('carts_%s' % user.id)
# 获取redis中的选中状态
cart_selected = redis_conn.smembers('selected_%s' % user.id)

# 将redis中的数据构造成跟cookie中的格式一致,方便统一查询
cart_dict = {}
for sku_id, count in redis_cart.items():
cart_dict[int(sku_id)] = {
'count': int(count),
'selected': sku_id in cart_selected
}
else:
# 用户未登录,查询cookies购物车
pass

2.查询cookie购物车

class CartsView(View):
"""购物车管理"""

def get(self, request):
"""展示购物车"""
user = request.user
if user.is_authenticated:
# 用户已登录,查询redis购物车
......
else:
# 用户未登录,查询cookies购物车
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 = {}

3.查询购物车SKU信息

class CartsView(View):
"""购物车管理"""

def get(self, request):
"""展示购物车"""
user = request.user
if user.is_authenticated:
# 用户已登录,查询redis购物车
......
else:
# 用户未登录,查询cookies购物车
......

# 构造购物车渲染数据
sku_ids = cart_dict.keys()
skus = SKU.objects.filter(id__in=sku_ids)
cart_skus = []
for sku in skus:
cart_skus.append({
'id':sku.id,
'name':sku.name,
'count': cart_dict.get(sku.id).get('count'),
'selected': str(cart_dict.get(sku.id).get('selected')), # 将True,转'True',方便json解析
'default_image_url':sku.default_image.url,
'price':str(sku.price), # 从Decimal('10.2')中取出'10.2',方便json解析
'amount':str(sku.price * cart_dict.get(sku.id).get('count')),
})
return JsonResponse({'code': 0, 'errmsg': 'OK', 'cart_skus': cart_skus})

 2.3 修改购物车

提示:在购物车页面修改购物车使用局部刷新的效果。

1. 修改购物车接口设计和定义

1.请求方式

选项

方案

请求方法

PUT

请求地址

/carts/

2.请求参数:JSON

参数名

类型

是否必传

说明

sku_id

int


商品SKU编号

count

int


商品数量

selected

bool


是否勾选

3.响应结果:JSON

字段

说明

sku_id

商品SKU编号

count

商品数量

selected

是否勾选

4.后端接口定义

class CartsView(View):
"""购物车管理"""

def put(self, request):
"""修改购物车"""
# 接收和校验参数
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,修改redis购物车
pass
else:
# 用户未登录,修改cookie购物车
pass

2. 修改购物车后端逻辑实现

1.接收和校验参数

class CartsView(View):
"""购物车管理"""

def put(self, request):
"""修改购物车"""
# 接收参数
json_dict = json.loads(request.body.decode())
sku_id = json_dict.get('sku_id')
count = json_dict.get('count')
selected = json_dict.get('selected', True)

# 判断参数是否齐全
if not all([sku_id, count]):
return http.HttpResponseBadRequest('缺少必传参数')
# 判断sku_id是否存在
try:
sku = SKU.objects.get(id=sku_id)
except SKU.DoesNotExist:
return http.HttpResponseBadRequest('商品sku_id不存在')
# 判断count是否为数字
try:
count = int(count)
except Exception:
return http.HttpResponseBadRequest('参数count有误')

# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,修改redis购物车
pass
else:
# 用户未登录,修改cookie购物车
pass

2.修改Redis购物车

class CartsView(View):
"""购物车管理"""

def put(self, request):
"""修改购物车"""
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,修改redis购物车
redis_conn = get_redis_connection('carts')
pl = redis_conn.pipeline()
# 因为接口设计为幂等的,直接覆盖
pl.hset('carts_%s' % user.id, sku_id, count)
# 是否选中
if selected:
pl.sadd('selected_%s' % user.id, sku_id)
else:
pl.srem('selected_%s' % user.id, sku_id)
pl.execute()

# 创建响应对象
cart_sku = {
'id':sku_id,
'count':count,
'selected':selected,
'name': sku.name,
'default_image_url': sku.default_image.url,
'price': sku.price,
'amount': sku.price * count,
}
return http.JsonResponse({'code':0, 'errmsg':'修改购物车成功', 'cart_sku':cart_sku})
else:
# 用户未登录,修改cookie购物车
pass

3.修改cookie购物车

class CartsView(View):
"""购物车管理"""

def put(self, request):
"""修改购物车"""
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,修改redis购物车
......
else:
# 用户未登录,修改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 = {}
# 因为接口设计为幂等的,直接覆盖
cart_dict[sku_id] = {
'count': count,
'selected': selected
}
# 将字典转成bytes,再将bytes转成base64的bytes,最后将bytes转字符串
cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()

# 创建响应对象
cart_sku = {
'id': sku_id,
'count': count,
'selected': selected,
'name': sku.name,
'default_image_url': sku.default_image.url,
'price': sku.price,
'amount': sku.price * count,
}
response = http.JsonResponse({'code':0, 'errmsg':'修改购物车成功', 'cart_sku':cart_sku})
# 响应结果并将购物车数据写入到cookie
response.set_cookie('carts', cookie_cart_str, max_age=7*24*3600)
return response

2.4 删除购物车

提示:在购物车页面删除购物车使用局部刷新的效果。

1. 删除购物车接口设计和定义

1.请求方式

选项

方案

请求方法

DELETE

请求地址

/carts/

2.请求参数:JSON

参数名

类型

是否必传

说明

sku_id

int


商品SKU编号

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

4.后端接口定义

class CartsView(View):
"""购物车管理"""

def delete(self, request):
"""删除购物车"""
# 接收和校验参数
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,删除redis购物车
pass
else:
# 用户未登录,删除cookie购物车
pass

2. 删除购物车后端逻辑实现

1.接收和校验参数

class CartsView(View):
"""购物车管理"""

def delete(self, request):
"""删除购物车"""
# 接收参数
json_dict = json.loads(request.body.decode())
sku_id = json_dict.get('sku_id')

# 判断sku_id是否存在
try:
SKU.objects.get(id=sku_id)
except SKU.DoesNotExist:
return http.HttpResponseBadRequest('商品不存在')

# 判断用户是否登录
user = request.user
if user is not None and user.is_authenticated:
# 用户未登录,删除redis购物车
pass
else:
# 用户未登录,删除cookie购物车
pass

2.删除Redis购物车

class CartsView(View):
"""购物车管理"""

def delete(self, request):
"""删除购物车"""
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user is not None and user.is_authenticated:
# 用户未登录,删除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()

# 删除结束后,没有响应的数据,只需要响应状态码即可
return http.JsonResponse({'code': 0, 'errmsg': '删除购物车成功'})
else:
# 用户未登录,删除cookie购物车
pass

3.删除cookie购物车

class CartsView(View):
"""购物车管理"""

def delete(self, request):
"""删除购物车"""
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user is not None and user.is_authenticated:
# 用户未登录,删除redis购物车
......
else:
# 用户未登录,删除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': 0, '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=7*24*3600)
return response

 2.5 全选购物车

提示:在购物车页面修改购物车使用局部刷新的效果。

1. 全选购物车接口设计和定义

1.请求方式

选项

方案

请求方法

PUT

请求地址

/carts/selection/

2.请求参数:JSON

参数名

类型

是否必传

说明

selected

bool


是否全选

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

4.后端接口定义

class CartsSelectAllView(View):
"""全选购物车"""

def put(self, request):
# 接收和校验参数
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,操作redis购物车
pass
else:
# 用户未登录,操作cookie购物车
pass

2. 全选购物车后端逻辑实现

1.接收和校验参数

class CartsSelectAllView(View):
"""全选购物车"""

def put(self, request):
# 接收参数
json_dict = json.loads(request.body.decode())
selected = json_dict.get('selected', True)

# 校验参数
if selected:
if not isinstance(selected, bool):
return http.HttpResponseBadRequest('参数selected有误')

# 判断用户是否登录
user = request.user
if user is not None and user.is_authenticated:
# 用户已登录,操作redis购物车
pass
else:
# 用户已登录,操作cookie购物车
pass

2.全选Redis购物车

class CartsSelectAllView(View):
"""全选购物车"""

def put(self, request):
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user is not None and user.is_authenticated:
# 用户已登录,操作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': 0, 'errmsg': '全选购物车成功'})
else:
# 用户已登录,操作cookie购物车
pass

3.全选cookie购物车

class CartsSelectAllView(View):
"""全选购物车"""

def put(self, request):
# 接收和校验参数
......

# 判断用户是否登录
user = request.user
if user is not None and user.is_authenticated:
# 用户已登录,操作redis购物车
......
else:
# 用户已登录,操作cookie购物车
cart = request.COOKIES.get('carts')
response = http.JsonResponse({'code': 0, '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=7*24*3600)

return response

2.6 合并购物车

需求:用户登录时,将​cookie​购物车数据​合并​​Redis​购物车数据中。

提示:

  • ​QQ登录​​​和​​账号登录​​时都要进行购物车合并操作。

1. 合并购物车逻辑分析

1.合并方向:cookie购物车数据合并到Redis购物车数据中。
2.合并数据:购物车商品数据和勾选状态。
3.合并方案:
3.1 Redis数据库中的购物车数据保留。
3.2 如果cookie中的购物车数据在Redis数据库中已存在,将cookie购物车数据覆盖Redis购物车数据。
3.3 如果cookie中的购物车数据在Redis数据库中不存在,将cookie购物车数据新增到Redis。
3.4 最终购物车的勾选状态以cookie购物车勾选状态为准。

2. 合并购物车逻辑实现

新建文件:​​carts.utils.py​

import base64
import pickle
from django_redis import get_redis_connection

def merge_cart_cookie_to_redis(request, user, response):
"""
登录后合并cookie购物车数据到Redis
:param request: 本次请求对象,获取cookie中的数据
:param response: 本次响应对象,清除cookie中的数据
:param user: 登录用户信息,获取user_id
:return: response
"""
# 获取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')

return response

3. 账号和QQ登录合并购物车

在​​users.views.py​​​和​​oauth.views.py​​文件中调用合并购物车的工具方法

# 合并购物车

response = merge_cart_cookie_to_redis(request=request, user=user, response=response)

三、展示商品页面简单购物车

美多商城项目之购物车存储方案、购物车管理、展示商品页面简单购物车_django_04

需求:用户鼠标悬停在商品页面右上角购物车标签上,以下拉框形式展示当前购物车数据。

1. 简单购物车数据接口设计和定义

1.请求方式

选项

方案

请求方法

GET

请求地址

/carts/simple/

2.请求参数:

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

cart_skus[ ]

简单购物车SKU列表

id

购物车SKU编号

name

购物车SKU名称

count

购物车SKU数量

default_image_url

购物车SKU图片

{
"code":"0",
"errmsg":"OK",
"cart_skus":[
{
"id":1,
"name":"Apple MacBook Pro 13.3英寸笔记本 银色",
"count":1,
"default_image_url":"http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrPB4GAWkTlAAGuN6wB9fU4220429"
},
......
]
}

4.后端接口定义

class CartsSimpleView(View):
"""商品页面右上角购物车"""

def get(self, request):
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,查询Redis购物车
pass
else:
# 用户未登录,查询cookie购物车
pass

# 构造简单购物车JSON数据
pass

2. 简单购物车数据后端逻辑实现

1.查询Redis购物车

class CartsSimpleView(View):
"""商品页面右上角购物车"""

def get(self, request):
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,查询Redis购物车
redis_conn = get_redis_connection('carts')
redis_cart = redis_conn.hgetall('carts_%s' % user.id)
cart_selected = redis_conn.smembers('selected_%s' % user.id)
# 将redis中的两个数据统一格式,跟cookie中的格式一致,方便统一查询
cart_dict = {}
for sku_id, count in redis_cart.items():
cart_dict[int(sku_id)] = {
'count': int(count),
'selected': sku_id in cart_selected
}
else:
# 用户未登录,查询cookie购物车
pass

# 构造简单购物车JSON数据
pass

2.查询Redis购物车

class CartsSimpleView(View):
"""商品页面右上角购物车"""

def get(self, request):
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,查询Redis购物车
......
else:
# 用户未登录,查询cookie购物车
cart_str = request.COOKIES.get('carts')
if cart_str:
cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
else:
cart_dict = {}

3.构造简单购物车JSON数据

class CartsSimpleView(View):
"""商品页面右上角购物车"""

def get(self, request):
# 判断用户是否登录
user = request.user
if user.is_authenticated:
# 用户已登录,查询Redis购物车
......
else:
# 用户未登录,查询cookie购物车
......

# 构造简单购物车JSON数据
cart_skus = []
sku_ids = cart_dict.keys()
skus = SKU.objects.filter(id__in=sku_ids)
for sku in skus:
cart_skus.append({
'id':sku.id,
'name':sku.name,
'count':cart_dict.get(sku.id).get('count'),
'default_image_url': sku.default_image.url
})

# 响应json列表数据
return http.JsonResponse({'code':0, 'errmsg':'OK', 'cart_skus':cart_skus})

 

 

 

 

举报

相关推荐

0 条评论