#前言:
在最近十天我会用Python做一个购物类电商项目,会用到Django+Mysql+Redis+Vue等。
今天是第六天,主要负责撰写编写关于商品购物车的编写,以及相应的增删改查。若是有不懂大家可以先阅读我的前六篇博客以能够顺承。
若是大家基础有不懂的,小编前面已经关于Django博客都更新完了,大家可以自行查看。若是有需要更改的地方欢迎大家指正,同时也欢迎大家关注点赞收藏等待后续,小编会尽力更新优质博客。
在此我会直接继承上一篇博客继续往下写。
十四、购物车:
关于设计购物车的思路很简单,首先就是能获取到我们商品的数据(主要以id为媒介)将其能够相应到前端页面吗,其次关于其它操作我在下面会详细撰写。
1、响应添加购物车数据:
创建应用实现购物车的功能操作 —— carts
配置 redis 数据库缓存购物车中的商品数据:
# 缓存 购物车商品数据
"carts" : {
"BACKEND" : "django_redis.cache.RedisCache",
"LOCATION" : "redis://127.0.0.1:6379/3",
"OPTIONS" : {
"CLIENT_CLASS" : "django_redis.client.DefaultClient"
}
},
关于相应页面和购物车添加:
# 购物车页面
path('carts/' , views.CartsView.as_view() , name='carts'),
class CartsView(View):
'''
响应购物车页面
'''
def get(self , request):
# 响应页面
return render(request , 'cart.html')
def post(self , request):
# 购物车商品添加 {sku_id: 3, count: 1}
sku_dict = json.loads(request.body.decode())
sku_id = sku_dict.get("sku_id")
count = sku_dict.get("count")
selected = sku_dict.get("selected" , True)
try:
SKU.objects.get(id=sku_id)
except Exception:
return HttpResponseForbidden('商品不存在')
user = request.user
redis_conn = get_redis_connection("carts")
# user_id = {sku_id:count , sku_id2:count}
redis_conn.hincrby('cart_%s'%user.id , sku_id , count)
if selected:
# 结果为 True 保存勾选状态
redis_conn.sadd('selected_%s'%user.id , sku_id)
return JsonResponse({'code':RETCODE.OK , 'errmsg':'OK'})
思路也很简单,这个post请求主要是负责将我们post请求到的数据(也就是我们需要添加的商品)获取到,注意因为是json数据类型,所有需要解码。其次将获取到的数据按照商品唯一的商品id将其存储到reedis数据库,其中注意有一个关于是否勾选的选项:
同样的如果你选择勾选的话就要将其保存到redis数据库中。
2、渲染购物车页面:
渲染前端页面的思路:就是将我们需要响应到前端的商品数据按照get请求获取到,将他们存储到一个字典当中,然后将数据一个个的按照商品id将要相应的数据存储到元组当中,最后响应传递给前端页面。
class CartsView(View):
'''
响应购物车页面
'''
def get(self , request):
# 响应页面
user = request.user
redis_conn = get_redis_connection("carts")
redis_cart = redis_conn.hgetall('cart_%s'%user.id)
redis_selected = redis_conn.smembers('selected_%s'%user.id)
# cart_dict = {sku1:{count:150 , selected:true} , sku2:{},……}
cart_dict = {}
for sku_id , count in redis_cart.items():
cart_dict[int(sku_id)] = {
'count' : int(count),
'selected' : sku_id in redis_selected
}
# 获取购物车中的所有商品数据
sku_ids = cart_dict.keys()
skus = SKU.objects.filter(id__in=sku_ids)
cart_skus = []
for sku in skus:
cart_sku_dict = {
"id" : sku.id,
"name" : sku.name,
'price' : str(sku.price),
'count' : cart_dict.get(sku.id).get('count'),
'selected' : str(cart_dict.get(sku.id).get("selected")),
'amount' : str(sku.price * cart_dict.get(sku.id).get('count')),
'default_image_url': STATIC_URL+'images/goods'+sku.default_image.url+'.jpg'
}
cart_skus.append(cart_sku_dict)
context = {'cart_skus':cart_skus}
return render(request , 'cart.html' , context=context)
修改 cart.html 对应标签的内容
<ul class="cart_list_td clearfix" v-for="(cart_sku , index) in carts" v-cloak>
<li class="col01"><input type="checkbox" name="" v-model="cart_sku.selected" @checked="update_selected(index)"></li>
<li class="col02"><img :src="cart_sku.default_image_url"></li>
<li class="col03">[[ cart_sku.name ]]</li>
<li class="col04">台</li>
<li class="col05">[[ cart_sku.price ]]元</li>
<li class="col06">
<div class="num_add">
<a @click="on_add(index)" class="add fl">+</a>
<input type="text" class="num_show fl" v-model="cart_sku.count" @blur="on_input(index)">
<a @click="on_minus(index)" class="minus fl">-</a>
</div>
</li>
<li class="col07">[[ cart_sku.amount ]]元</li>
<li class="col08"><a @click="on_delete(index)">删除</a></li>
</ul>
<ul class="settlements">
<li class="col01"><input type="checkbox" name="" @change="on_selected_all" v-model="selected_all"></li>
<li class="col02">全选</li>
<li class="col03">合计(不含运费):<span>¥</span><em>[[ total_selected_amount ]]</em><br>共计<b>[[ total_selected_count ]]</b>件商品</li>
<li class="col04"><a href="place_order.html">去结算</a></li>
</ul>
<script type="text/javascript">
let carts = {{ cart_skus|safe }};
</script>
3、修改购物车购买数量:
修改 购买数量的思路和前面一样,我们要做的就是和前面添加购物车的思路唯一思路上不一样的就是响应出来的价钱要的是数量乘以原先的价格,其次还有一点要注意的是我们要的是勾选了select的数据。
注意,它的请求方式为put请求:
def put(self , request):
# {sku_id: 6, count: 3, selected: true}
sku_dict = json.loads(request.body.decode())
sku_id = sku_dict.get("sku_id")
count = sku_dict.get("count")
selected = sku_dict.get("selected" , True)
try:
sku = SKU.objects.get(id=sku_id)
except Exception:
return HttpResponseForbidden('商品不存在')
user = request.user
redis_conn = get_redis_connection("carts")
redis_conn.hincrby('cart_%s'%user.id , sku_id , count)
if selected:
redis_conn.sadd('selected_%s'%user.id , sku_id)
else:
redis_conn.srem('selected_%s' % user.id, sku_id)
cart_sku_dict = {
"id": sku.id,
"name": sku.name,
'price': sku.price,
'count': count,
'selected': selected,
'amount': sku.price * count ,
'default_image_url': STATIC_URL + 'images/goods/' + sku.default_image.url + '.jpg'
}
return JsonResponse({'code':RETCODE.OK , 'errmsg':'OK', 'cart_sku':cart_sku_dict})
4、删除购物车商品数据:
删除购物车商品数据的思路也很简单,主要是获取到delete请求获取到的需要删除的数据后我们将其按照id将数据从redis数据库删除。
def delete(self , request):
# 删除购物车数据
sku_dict = json.loads(request.body.decode())
sku_id = sku_dict.get('sku_id')
user = request.user
redis_conn = get_redis_connection("carts")
redis_conn.hdel('cart_%s' % user.id, sku_id)
redis_conn.srem('selected_%s' % user.id, sku_id)
return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
5、全选购物车商品数据:
全选购物车商品的最主要思路就是来一个循环将其选择状态都保存到redis数据库。
# 全选购物车
path('carts/selection/' , views.CratSelectAllView.as_view()),
class CratSelectAllView(View):
'''
全选购物车商品
'''
def put(self , request):
selected_dict = json.loads(request.body.decode())
selected = selected_dict.get('selected')
user = request.user
redis_conn = get_redis_connection("carts")
redis_cart = redis_conn.hgetall('cart_%s' % user.id)
sku_ids = redis_cart.keys()
if selected:
redis_conn.sadd('selected_%s' % user.id, *sku_ids)
else:
for sku_id in sku_ids:
redis_conn.srem('selected_%s' % user.id, sku_id)
return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
6、浏览记录:
同样的将浏览记录存储在redis数据库当中:
# 缓存 浏览记录
"history" : {
"BACKEND" : "django_redis.cache.RedisCache",
"LOCATION" : "redis://127.0.0.1:6379/4",
"OPTIONS" : {
"CLIENT_CLASS" : "django_redis.client.DefaultClient"
}
},
在用户的应用下实现视图操作:
浏览记录的应用主要思路是:先将我们浏览的数据get请求到它的信息,然后将其存入redis数据库,然后按照post请求将它负责去重-保存-截取的思路(因为在一定时间内连续访问同一商品我们之存入最近访问的一次)。
# 用户的浏览记录
path('browse_histories/' , views.UserBrowerHistoryView.as_view()),
class UserBrowerHistoryView(View):
'''
浏览记录
'''
def get(self , request):
redis_conn = get_redis_connection('history')
user = request.user
sku_ids = redis_conn.lrange("history_%s"%user.id , 0 , -1)
skus = []
for sku_id in sku_ids:
sku = SKU.objects.get(id = sku_id)
sku_dict = {
'id': sku.id,
'name' : sku.name,
'price' : sku.price,
'default_image_url' : STATIC_URL + 'images/goods/' + sku.default_image.url + '.jpg'
}
skus.append(sku_dict)
return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK' , 'skus':skus})
def post(self , request):
sku_dict = json.loads(request.body.decode())
sku_id = sku_dict.get('sku_id')
try:
SKU.objects.get(id=sku_id)
except Exception:
return HttpResponseForbidden('商品不存在')
redis_conn = get_redis_connection('history')
user = request.user
# 去重
redis_conn.lrem("history_%s"%user.id , 0 ,sku_id)
# 保存
redis_conn.lpush("history_%s"%user.id , sku_id)
# 截取
redis_conn.ltrim("history_%s"%user.id , 0 , 20)
return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
#总结:
关于购物车的实现我们最主要的思路还是按照将其从页面请求到需要操作的数据,然后后端请求后响应回前端页面,而数据的存储我们存储到redis数据库当中,因为购物车是在可以不断刷新的,用redis的效率更高一点。
最后,若是大家发现小编的博客需要更改的地方欢迎各位评论指正,同时欢迎大家点赞关注小编,您的支持将是小编变强的最大动力!