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

posted @ 2023-02-18 14:32  dayu2020  阅读(170)  评论(0编辑  收藏  举报