django购物车的实现
1 购物车的实现问题思路
购物车需求分析:
1 未登陆和已登陆都保存到用户的购物车数据。
2 用户可以对购物车进行增删改查;
3 购物车有选择状态,只有选中的状态才能生成订单;
4 用户登陆时,合并cookie
涉及到技术栈:
1 redis 的hash和set 的操作,增删改查及管道技术
2 cooike 的设置和删除以及解码和加码的
技术实现:
对于未登陆用户,购物车数据使用浏览器cookie保存
对于已登陆的用户,购物车在后端使redis保存,具体存储结果
hash {
使用幂等技术,多次点击完成后,得到最终的数量
数据库redis的设计:
hash: user_id sku_id count
set : sku_id (选中商品)
redis 中管道技术的实现:
1 创建管道实例
2 添加执行操作
3 管道统一执行
Cookie保存数据
涉及的知识点:
1 获取cookie中的card值
car_str=request.COOKIES.get(cart)
2 如果不为空,进行解码, 先进行二进制转换encode,然后base64.b64decode,然后再转换成字典
cart_dict=picker.loads(base64.b64decode(cart_str.encode()))
3 判断sku_id 存在 if sku_id in card_dict,
origin_count=card_dict[sku_id]['count']
count+=origin_count
4 进行更新数据
cart_dict[sku_id]={
'count':count,
'selected':selected
5 进行加密
card=picker.dumps(base64.b64encode(cart_dict.decode()))
6 保存cookie
response.set_cookie('card',card,24*3600 1
#有关cookie 解码和加密写单独函数进行实现
2 购物车的增加
2.1增加业务的思路
逻辑分析
# 1 前端发送增加请求,post请求,获取selected,sku_id ,count
# 2 首先检查商品
# 3 检查是用户是否登陆,
# 3.1 如何登陆,则存储到redis,
# 3.1.1 登陆Redis,
# 使用 redis hash user.id {sku_id:count}
# 使用 redis.con.hset('card_%s'%user.id, sku_id,count)
# 3.1.2 使用 hiscrby进行累计存储
redis.con.hincry('card_%s'%user.id,sku_id,count)
# 3.1.3 如何selected 选中,则,suk_id 存放到set
if selected:
redis.con.sadd('card_seleted_%s'%user.id .sku_id
# 3.2 没有登陆,存储cookie中
# 3.2.1获取cookie 的值
# 3.2.2 不存在,则创建 cart={},
# 3.2.3重新写入cooie 中,返回结果
# 4 返回结果
2.2 代码实现
def post(self,request):
# 1 前端发送增加请求,post请求,获取selected,sku_id ,count
dict_data=json.loads(request.body.decode())
sku_id=dict_data.get('sku_id')
count=dict_data.get('count')
selected=dict_data.get('selected')
# 2 首先检查商品
if not all([sku_id,count]):
return JsonResponse({'code':401,'errmsg':'传递的参数不全'})
try:
sku=SKU.objects.get(id=sku_id)
except SKU.DoesNotExist:
return JsonResponse({'code':402,'errmsg':'增加到购物车商品不存在'})
# 3 检查是用户是否登陆,
try:
user=request.user
except Exception:
user=None
# 3.1 如何登陆,则存储到redis,
# 3.1.1 登陆Redis,
if user is None and user.is_authenticated:
redis_con = get_redis_connection(CARD_CACHE_ALIAS)
rc_p = redis_con.pipeline()
# 购物车中无没有该商品,没有则增加,有则进行累计实现增量
if not rc_p.hexists('cart_%s'%user.id,sku_id):
rc_p.hset('cart_%s'% user.id,sku_id,count)
# 3.1.2使用hiscrby进行累计存 储
else:
rc_p.hincrby('cart_%s'%user.id, sku_id, count)
print(rc_p.hincrby('cart_%s'%user.id, sku_id, count))
# 3.1.3 如何select 选中,则,suk_id 存放到set
if selected:
rc_p.sadd('carts_selected_%s'%user.id,sku_id)
# 让管道集中处理
rc_p.execute()
return JsonResponse({'code': 200, 'errmsg': '完成添加'})
# 3.2 没有登陆,存储cookie中
else:
# 1获取cookie 的值
cart_dict=get_cookie_key(request,'cart')
# cart_str = request.COOKIES.get('cart')
# #2 判断是否为空,为空
# if cart_str is not None:
# cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
# else:
# 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
}
response=up_cookie_key('cart',cart_dict)
return response
# 4 返回结果
3 购物车的查询
3.1购物车查询的思路分析:
# 1 获取get请求,先判断是否为登陆客户
# 2 如果是登陆客户
# 连接redis
# 获取set的值
# 获取card_%对于的值
# 循环遍历获取sku_id
# 3 如果非登陆客户
# 获取cooke中cart的值card_dict
'''
3.2 代码实现
# 1 获取get请求先判断是否为登陆客户
try:
user=request.user
except:
user=None
# 2 如果是登陆客户
if user is not None and user.is_authenticated:
# 连接redis
# 获取card_%对于的
redis_con=get_redis_connection(CARD_CACHE_ALIAS)
# 获取set的值
cart_seleted=redis_con.smembers('cart_selected_%s'%user.id)
# 循环遍历获取sku_id
cart_redis=redis_con.hgetall('cart_%s'%user.id)
print(cart_redis)
print(type(cart_redis))
cart_data={}
for sku_id,count in cart_redis.items():
count=int(count.decode())
cart_data[sku_id.decode()]= {
'count':count,
'selected':sku_id in cart_seleted
}
# 3 如果非登陆客户
# 获取cooke中cart的值card_dict
else:
cart_data=get_cookie_key(request,'cart')
print(cart_data)
print(type(cart_data))
cart_list=[]
for sku_id in cart_data:
print(sku_id)
try:
sku=SKU.objects.get(id=sku_id)
except :
continue
cart_list.append({
'id': sku_id,
'name':sku.name,
'price':sku.price,
'count': cart_data[sku_id]['count'],
'selected':cart_data[sku_id]['selected']
})
return JsonResponse({'code':200,'data':cart_list})
4 购物车修改
4.1购物车修改的思路
# 1 获取请求参数
# 2 判断用户是否登陆
# 3 登陆,重置redis数量,(商品数量,默认选中)
# 4 未登陆 ,获取cookie card_data,修改数量
4.2 代码实现
def put(self,request):
# 1 获取请求参数
body_data = json.loads(request.body.decode())
sku_id = body_data.get('sku_id')
selected = body_data.get('selected')
count = body_data.get('count')
if sku_id is None:
return JsonResponse({'code': 401, 'errmsg': '参数不全'})
try:
sku = SKU.objects.get(id=sku_id)
except SKU.DoesNotExist:
return JsonResponse({'code': 401, 'errmsg': '商品错误'})
# 2 判断用户是否登陆
try:
user = request.user
except:
user = None
# 3 登陆,redis数量,(删除sku_id 相关 记录,如果选中,取消选中)
if user is not None and user.is_authenticated:
redis_con = get_redis_connection(CARD_CACHE_ALIAS)
redis_con.hset('card_%s'%user.id,sku_id,count)
if selected:
redis_con.sdd('card_selected_%s'%user.id,sku_id)
else:
redis_con.srem('card_selected_%s'%user.id,sku_id)
return JsonResponse({'code':200})
# 4 未登陆 ,获取cookie card_data,修改数量
else:
card_dict=get_cookie_key(request,'card')
origin_count=card_dict[sku_id]['count']
count+=origin_count
card_dict[sku_id]={
'count':count,
'selected':selected
}
response=up_cookie_key('card',card_dict)
return response
5 购物车删除
5.1购物车删除的思路
# 1 获取请求参数
# 2 判断用户是否登陆
# 3 登陆,redis数量,(删除sku_id 相关 记录,如果选中,取消选中)
# 4 未登陆 ,获取cookie card_data,删除相关记录
5.2 代码实现
def delete(self,request):
# 1 获取请求参数
body_data=json.loads(request.body.decode())
sku_id=body_data.get('sku_id')
if sku_id is None:
return JsonResponse({'code': 401, 'errmsg': '参数不全'})
try:
sku = SKU.objects.get(id=sku_id)
except SKU.DoesNotExist:
return JsonResponse({'code': 401, 'errmsg': '商品错误'})
# 2 判断用户是否登陆
try :
user=request.user
except :
user=None
# 3 登陆,redis数量,(删除sku_id 相关 记录,如果选中,取消选中)
if user is not None and user.is_authenticated:
redis_con=get_redis_connection(CARD_CACHE_ALIAS)
redis_con.hdel('cart_%s'%user.id,sku_id)
redis_con.srem('cart_select_%s'%user.id,sku_id)
return JsonResponse({'code':200})
else:
# 4 未登陆 ,获取cookie card_data,删除相关记录
cart_dict=get_cookie_key(request,'cart')
if sku_id in cart_dict:
del cart_dict[sku_id]
response=up_cookie_key('cart',cart_dict)
return response
6 购物车的合并问题
合并问题就是,cookie和redis的购物车商品记录的取舍问题,本思路采用,以cooike为准,如果,有则覆盖,没有则增加;
6.1 功能实现思路
合并cookie 购物车到redis方案有多种,本次采用用cookie为主,
cookie 数据 { reids 数据 {
'1': { hash '1': count ‘4’:count
'count': 1,
'selected':1} set { sku}
合并的的业务逻辑:
# 1 从cookie 读取cart的数据;返回是一个字典 cookie_dict,但是redis存储的二进制元素,需要进行单独decode
sku_list=[sku_id.decode() for sku_id in redis_data] 把字典的key 生成一个列表生成式
# 2 遍历cookie_dict
# 2.1打开 redis_con 直接向跟sku_id 向redis hash 进增加数据,有则修改,以cooike为主,没有则增加
# redis.con.hset('cart_%s'%user.id,sku_id, cookie[sku_id]['count'])
# 2.2判断 cookie[sku_id]['selected']为真,则 进行 redis_con.sadd('cart_selected_%s'%user.id,sku_id),
# 否则,判断 skui_id 是否在集合中,存在,则删除
# 3 删除cookie, 设置和删除cookie必须使用response
# response.delete_cookie('cart') ;退出的时候cart换成用户名即可
'''
6.2 功能实现代码
在系统登陆后直接调用该函数即可
from django.http import JsonResponse
from movice_fuli.settings import CARD_CACHE_ALIAS
def merege_cookie_redis(request,response):
# 1 从cookie 读取cart的数据;返回是一个字典 cookie_dict
card_dict = get_cookie_key(request, 'cart')
redis_con = get_redis_connection(CARD_CACHE_ALIAS)
user=request.user
redis_data=redis_con.hgetall('cart_%s'%user.id)
sku_list=[sku_id.decode() for sku_id in redis_data]
rp=redis_con.pipeline()
# 2 遍历cookie_dict
for sku_id in card_dict:
if sku_id in sku_list:
rp.hset('cart_%s'%user.id,sku_id,card_dict[sku_id]['count'])
if card_dict[sku_id]['selected']:
rp.sadd('cart_selected_%s'%user.id,sku_id)
else:
rp.srem('cart_selected_%s'%user.id,sku_id)
else:
rp.hset('cart_%s' % user.id, sku_id, card_dict[sku_id]['count'])
rp.execute()
# 3删除cookie信息
response.delete_cookie('cart')
return response
django购物车的实现的更多相关文章
- Django 购物车模板
url from django.contrib import admin from django.urls import path, re_path from django.urls import i ...
- $Django 路飞之显示视频,Redis存购物车数据,优惠卷生成表,优惠卷的一个领取表。(知识小回顾)
知识小回顾之json序列化问题 精髓:支持python的几种数据类型(注意不是对象,不能放对象),其次是tuple变list. ensure_ascii:默认值True,如果dict内含有non-AS ...
- django项目中购物车的实现
对于做项目而言,最重要的是分析清楚自己负责模块的思路,确定思路后,把每一步实现的步骤确定后,根据步骤,去实现代码,测试. 购物车的逻辑: 登录用户可以添加购物车,未登陆用户页可以添加到购物车 ...
- Django实战(13):在session中保存购物车
现在,我们有了一个产品目录界面,用户如果看到满意的产品,就可以将其放入购物车.下面就让我们来实现购物车的功能. 首先要做一下简单的分析和设计.购物车应该显示一系列产品的清单,其中列出了买方选中的产品. ...
- django 商城项目之购物车以及python中的一些redis命令
最近在用django restframe框架做一个商城项目,有一个关于购物车的业务逻辑,是用cookie和redis存储的购物车信息,在这里记录一下. 完成一个商城项目,如果不做一个购物车,就是十分可 ...
- Django电商项目---完成购物车页面day4
创建购物车项目App python manage.py startapp df_cart 初始化项目: manas/urls.py manas/settings.py 创建新文件:df_cart/ur ...
- Django 实现购物车功能
购物车思路:使用 session 功能识别不同浏览器用户,使得用户不管是否登录了网站,均能够把想要购买的产品放在某个地方,之后随时可以显示或修改要购买的产品,等确定了之后再下订单,购物车可以用来暂存商 ...
- django中的构造字典(二级菜单,评论树,购物车)
1.构造父子结构: 1.1需求样式 客户列表 customer_list /customer/list/ -----> 添加客户 customer_add /customer/add/ ---- ...
- Django day 37 网站视频的播放,购物车接口,优惠券表分析
一:网站视频的播放, 二:购物车接口, 三:优惠券表分析
- python代码实现购物车(django的redis与vue)
安装模块 pip install django-redis 后端代码 # 购物车 class CartView(APIView): # 初始化函数 def __init__(self): self.c ...
随机推荐
- 如何用Python对股票数据进行LSTM神经网络和XGboost机器学习预测分析(附源码和详细步骤),学会的小伙伴们说不定就成为炒股专家一夜暴富了
前言 最近调研了一下我做的项目受欢迎程度,大数据分析方向竟然排第一,尤其是这两年受疫情影响,大家都非常担心自家公司裁员或倒闭,都想着有没有其他副业搞搞或者炒炒股.投资点理财产品,未雨绸缪,所以不少小伙 ...
- Windows系统下Dos命令记录
# 切换到F:\test\目录 /d 参数可以直接切换,不需要先切换盘符 cd /d F:\test\ # 创建文件夹test md tset # 删除文件夹test rd test # 创建文件te ...
- [ElasticSearch]#Search Guard#sgadmin参数说明
sgadmin.sh/sgadmin.bat是Elastic Search的开源安全组件Search Guard内的可执行脚本. 在修改SG组件的用户角色.权限.密码时,需使用到此脚本. 在修改完Se ...
- odoo 开发入门教程系列-约束(Constraints)
约束(Constraints) 上一章介绍了向模型中添加一些业务逻辑的能力.我们现在可以将按钮链接到业务代码,但如何防止用户输入错误的数据?例如,在我们的房地产模块中,没有什么可以阻止用户设置负预期价 ...
- 从桌面和应用内 Activity的启动流程
1.APP还没有被打开过从桌面启动 <1>首先桌面进程会像AMS服务发送startActivity的请求,AMS从system_service中去拿----一次IPC通信 <2> ...
- 【Spring注解驱动】(三)Servlet 3.0
前言 今天是7.21日,终于是看完了..暑假在家学习是真的差点意思 1 Servlet 3.0简介 Servlet 2.0是在web.xml中配置servlet filter.listener.Dis ...
- Golang爬虫:使用正则表达式解析HTML
之前所写的爬虫都是基于Python,而用Go语言实现的爬虫具有更高的性能. 第一个爬虫 使用http库,发起http请求 package main import ( "fmt" & ...
- 操作系统实验 & bochs 环境配置
wsl2 - Ubuntu 22.04 + VSCode + bochs + xfce4 + VcXsrv 笔者环境 wsl2 - Ubuntu 22.04 0. 安装WSL2 & VSCod ...
- java处理集合工具
public static <K, V> Map<K, V> parseListToMap(Collection<V> list, Function<V, K ...
- ntp导致其他线程卡顿原因总结
这个是在项目开发中遇到的一个比较严重的问题,第一影响到主界面的播放卡顿,第二影响到我这边线程同样卡顿,按道理来说两个没有数据交互的线程应该没有任何影响,改为detach模式也没用,最后定位到居然是单独 ...