Django 项目总结(11)- 购物车部分

购物车部分

基本功能:购物车的管理(区分用户登录和未登录)

业务需求
  • 在用户登录与未登录状态下,都可以保存用户的购物车数据
  • 用户可以对购物车数据进行增删改查
  • 用户对于购物车的勾选也要保存,在订单结算页面会使用勾选数据
  • 用户登录时,合并 cookie 中的购物车数据到 redis 中
技术实现
  • 对于未登录的用户,购物车数据使用浏览器 cookie 保存
  • 对于已登录的用户,购物车数据在后端使用 redis 保存



购物车数据存储设计

redis 保存已登录用户

分两个表进行保存

第一个表以哈希类型保存-购物车数据:

采用 hash 是因为每个用户要保存多个 sku_id 和 count 直接的对应关系

键: cart_用户id

值: {sku_id: count, sku_id: count, ……}

第二个表以 set 集合类型保存-购物车勾选记录

采用 set 是因为要对商品的勾选去重,但不需要保存商品的加入顺序,在表中只需要保存勾选状态就行

键: cart_selected_用户id

值: {sku_id, sku_id ….}




cookie 保存未登录用户
# 保存数据的格式

{
    sku_id: {
        "count": xxx,  // 数量
        "selected": True  // 是否勾选
    },
    sku_id: {
        "count": xxx,
        "selected": False
    },
    ...
}

在cookie中只能保存字符串数据,所以将上述数据使用pickle进行序列化转换 ,并使用base64编码为字符串,保存到cookie中。


pickle模块的使用

pickle模块是python的标准模块,提供了对于python数据的序列化操作,可以将数据转换为bytes类型,其序列化速度比json模块要高。

  • pickle.dumps() 将python数据序列化为bytes类型
  • pickle.loads() 将bytes类型数据反序列化为python的数据类型

base64模块的使用

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

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

python标准库中提供了base64模块,用来进行转换

  • base64.b64encode() 将bytes类型数据进行base64编码,返回编码后的bytes类型
  • base64.b64deocde() 将base64编码的bytes类型进行解码,返回解码后的bytes类型

使用 pickle 模块对数据进行原始数据和字节之间的转换

使用 base64 模块对数据进行字节和字符串之间的转换




添加到购物车

注意:

因为前端请求时携带了 Authorization 请求头(主要是 JWT),而如果用户未登录,此请求头的 JWT 无意义(没有值),为了防止 REST framework 框架在验证此无意义的 JWT 时抛出 401 异常,在视图中需要做两个处理

  • 重写perform_authentication()方法,此方法是REST framework检查用户身份的方法
  • 在获取request.user属性时捕获异常,REST framework在返回user时,会检查Authorization请求头,无效的Authorization请求头会导致抛出异常

前端传 token 的三种情况

  1. 传了 token,而且 token 是正确的,那么通过 request.user 可以直接拿到用户对象
  2. 传了 token,但 token 是错误的,那么调用 request.user 会抛出异常
  3. 没传 token,调用 request.user 会返回 AnonymousUser(匿名用户)
  • 写序列化器对前端传送过来的数据进行反序列化处理

  • Django 对 JWT 的验证可能会导致报错,我们需要重写 perform_authentication 方法,然后自己进行 JWT 验证(主要就是看 request 中能不能取出 user 对象),判断一下用户是否登录,然后根据登录状态进行不同的操作

  • 判断用户是否登录且通过 is_authenticated 验证(也就是通过账户名和密码判断用户是否存在)

  • 如果通过,用户已经登录,此时将数据保存到 redis 中,保存购物车数量数据,使用 hash 的命令 hincrby ,该命令可以对数量进行自增:

    • HINCRBY key field increment

      为哈希表 key 中的域 field 的值加上增量 increment

    保存勾选状态,使用 set 的命令 sadd ,该命令可以自动去重:

    • SADD key member [member …]

      将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。

  • 使用 pl 一次性进行提交并将数据返回

  • 如果没有通过,就将数据保存在 cookie 中,cookie 中只能保存字符串,判断一下 cookie 中是否有数据

    • 如果有数据,使用 encode() 对字符串进行编码,使用 base64 模块将编码过的字符串转换成二进制字节数据,使用 pickle 模块,将字节数据转换成字典数据方便操作,然后将当前要添加的数据添加到字典中,如果已经有这个商品,对数量进行增加操作
    • 如果没有数据,创建空字典,将数据加入

    最后使用 pickle 模块将字典转换为字节,base64 模块将字节转换为字符串,使用 decode() 将字符串解码,将字符串存入 cookie

  • 返回 response




查询购物车数据

用户点击 我的购物车 ,跳转页面,对购物车数据进行查询,然后进行展示

  • 还是区分登录和未登录状态,登录从 redis 中查询,未登录从 cookie 中查询
  • 区别就是从 redis 中查询出来的数据要将数据格式转换成 cookie 中一样的数据格式,这个方便进行传递,
  • 根据 sku_id 查询到所有的商品对象,为每个对象添加对应的 count 和 selected ;
  • 新闻 sku 表中没有 数量和勾选状态这两个字段,在序列化时添加上
  • 将数据序列化,返回前端需要的数据



修改购物车数据

用户对数据进行修改,进行保存,

在这里好像有个 幂等 和 非幂等 的区别:

幂等就是请求的数据和返回的数据一样,在这里就是进行数据覆盖操作;

非幂等就是请求的数据和返回的数据不一样,对数据进行增加操作

  • 对传过来的数据反序列化
  • 使用幂等模式,对数据进行覆盖操作,前端直接将商品的总数量传过来,进行覆盖操作
  • 对勾选状态进行判断,用户勾选了就新增,取消将将状态删除



删除购物车数据

删除购物车数据,只需要将 sku_id 传过来即可,

  • 反序列化数据,判断有没有当前这个商品
  • 然后根据登录状态,将对应的数据删除即可
  • 登录状态:
    • 使用 hdel 命令删除商品数量表中的数据
    • 使用 srem 命令删除勾选状态表中的数据
  • 未登录:cookie 中的数据是字典,使用 del 方法将字典中的数据删除



登录合并购物车

用户登录时,需要将 cookie 中的购物车数据合并到 redis 中,并清除 cookie 中的购物车数据。

因为在这里有两种登录方式,普通登录和 QQ 登录,这两种登录都需要进行数据合并,所以将合并的逻辑放到公共函数里实现。

  • 新建函数,函数需要三个参数,请求对象 request、响应对象 response、当前登录用户 user
  • 尝试从 request 中取出 cookie 中的购物车数据,没有直接返回,有,进行下一步的操作
  • 取出 redis 中的购物车数据
  • 遍历 cookie 购物车数据字典,取到 sku_id 和 selected_count_dict 字典,按照 redis 存储的数据格式将数据加入,如果有 redis 中已经有 sku_id ,对 count 其进行覆盖操作
  • 根据购物车状态进行操作,勾选添加,取消勾选,删除
  • 使用 response.delete_cookie(‘cart’) 方法清除 cookie 数据
  • 返回 response



修改普通登录视图

重写 rest_framework_jwt.views.ObtainJSONWebToken 类视图中的 post 方法来添加合并逻辑。

  • 重写方法
  • 不要重写 post 方法中的原始判断逻辑,使用 super 继承父类中的逻辑即可,该逻辑会返回 response 对象
  • 添加合并购物车逻辑,函数要传三个参数,从 serializer 对象中取到 user 对象,将三个参数传过去,得到最终的 response 对象,返回即可。
  • 修改登录的 url 路径,让登录时访问该视图



修改 QQ 登录视图

在最后登录成功前加上合并购物车逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值