购物车
后端
由于购物车数据量小,且数据变化比较频繁,所以采用Redis内存数据库来存储,采用的数据类型如下:
- 存储商品数据,采用hash结构,如cart_1:{3:5}。其中的数字部分分别代表用户id,加购的商品id,购买的该商品的数量。
- 存储商品的选中状态,采用set结构,如cart_selected_1: {3, 5,…}
集合中的数字为勾选的商品id。
Redis hash&set数据类型操作回顾:
python的操作方法
r = redis.Redis(host='localhost', port=6379, db=0)
#存储商品数据
r.hset('cart_1', key=2, value=3)
r.hget("cart_1", 2) #注意是字节数据byte类型
r.hdel("cart_1", 2) #删除
#存储集合数据
r.sadd("cart_selected_1", 2)
r.sadd("cart_selected_1", 2,3)
r.smembers("cart_selected_1")
r.srem("cart_selected_1", 2)
#关闭连接
r.close()
#添加购物车视图
class Cartview(APIView):
def post(self,request,goods_id):
#获取到中间件检测完登录,传递过来的用户信息
user=request.META.get('USER')
if not user:
return Response({
'code':400,
'msg':'用户未登录'
})
user_id=user['user_id']
r=redis.Redis(host='127.0.0.1',port=6379,password='redis密码')
key='cart:'+str(user_id)
#存入数据库
#先判断商品是否存在
goods_info=Goods.objects.filter(id=goods_id).first()
if not goods_info:
return Response({
'code':400,
'msg':'商品不存在'
})
cart={ #前端vuex里的数据结构
'id': goods_id, # 购物车id
'productID': goods_id, # 商品id
'productName': goods_info.sku_name, # 商品名称
'productImg': goods_info.img, # 商品图片
'price': goods_info.selling_price, # 商品价格
'num': 1, # 加购的商品数量
'maxNum': goods_info.stock, # 商品限购数量
'check': False # 是否勾选
}
#当前商品是否已经存在购物车
is_exist=r.hexists(key,goods_id)
if is_exist:
#判断一下商品数量是非法已经超出库存量
goods_count=r.hget(key,goods_id)#当前商品加入购物车的数量 返回的是byte类型
goods_count_int=int(goods_count.decode())
if goods_count_int>=goods_info.stock:
return Response({
'code':400,
'msg':'购物车商品已达到上限'
})
#购物车数量加1
r.hincrby(key,goods_id,1)
cart['num']=goods_count_int+1
return Response({
'code':201,
'msg':'商品已经在购物车,购物车数量加一',
'cart':cart
})
else:
#把商品添加到购物车
r.hset(key,goods_id,str(1))
return Response({
'code':200,
'msg':'加入购物车成功',
'cart':cart
})
# 查看购物车
class Showcartview(APIView):
def get(self,request):
user=request.META.get('USER') #获取到中间件检测完登录,传递过来的用户信息、
if not user:
return Response({
'code':400,
'msg':'用户未登录'
})
user_id=user['user_id']
#获取到redis里面存储的商品信息
r=redis.Redis(host='127.0.0.1',port=6379,password='redis密码')
key = 'cart:' + str(user_id)
goods_list=r.hgetall(key)
goods_all=[]
for (k,v) in goods_list.items():
k=k.decode() #商品id
v=v.decode() #商品加购数量
goods_info=Goods.objects.filter(id=k).first()
if not goods_info: #如果商品不存在,跳过该商品
continue
select_key = 'cart_select:%s' % user_id
is_exists=r.sismember(select_key,k)
info={ #前端vuex里的数据结构
'id': k, # 购物车id
'productID': k, # 商品id
'productName': goods_info.sku_name, # 商品名称
'productImg': goods_info.img, # 商品图片
'price': goods_info.selling_price, # 商品价格
'num': int(v), # 加购的商品数量
'maxNum': goods_info.stock, # 商品限购数量
'check': is_exists # 是否勾选
}
goods_all.append(info)
return Response({
'code':200,
'msg':'商品获取成功',
'goods':goods_all
})
配置路由
from django.urls import path
from goods import views
urlpatterns = [
path('cart/<int:goods_id>/',views.Cartview.as_view()), #购物车增删改
path('cart/',views.Showcartview.as_view()), #查看购物车
]
前端
找到相对应的vue文件
找到相关的功能函数进行配置
例如:Details.vue
methods: {
...mapActions(['unshiftShoppingCart','addShoppingCartNum']),
addShoppingCart() { //
// 判断是否登录,没有登录则显示登录组件
if (!this.$store.getters.getUser) {
this.$store.dispatch("setShowLogin", true);
return;
}
// 已经登录
console.log("@@getUser,已登录用户:", this.$store.getters.getUser)
// TODO 加入购物车数据,成功后管理 vuex 内容
this.$axios.post('/goods/cart/'+this.productID+'/',{},{
'headers':{
'token':localStorage.getItem('token')
}
}).then((result) => {
if (result.data.code==200){
this.unshiftShoppingCart(result.data.cart)
this.notifySucceed(result.data.msg)
// alert(result.data.msg)
}else if (result.data.code==201){
this.addShoppingCartNum(result.data.cart.productID)
this.notifySucceed(result.data.msg)
// alert(result.data.msg)
}else{
this.notifyError(result.data.msg)
}
}).catch((err) => {
console.log(err)
});
},
}
查看购物车
例如:App.vue
watch: {
// 管理vuex中的shoppingCart数据
getUser: function (val) {//val为登录的用户,如{"userName":'laufing'}
if (val === "") {
// 退出登录,清空购物车
this.setShoppingCart([]);//置空购物车,即state.shoppingCart=[]
} else {
// TODO 用户完成登录,获取该用户的购物车数据
this.$axios.get('/goods/cart/',{
'headers':{
'token':localStorage.getItem('token')
}
}).then((result) => {
if (result.data.code==200){
var goods_all=result.data.goods //暗道后台传过来的购物车数据
this.setShoppingCart(goods_all) //把购物车的数据,赋值到vuex里面
}else{
this.notiftError(result.data.msg)
}
}).catch((err) => {
console.log(err)
});
}
},
},