模型设计
- 模型设计:
订单信息
应该包含那些字段
- 订单号: order_id
- 下单用户: user
- 下单用户收货地址: address
- 商品总数: total_count
- 商品总价: total_amount
- 运费: freight
- 支付方式(本项目两种): pay_method
- 支付宝
- 货到付款
- 订单状态(6种): status
- 待支付
- 待发货
- 待收货
- 待评价
- 已完成
- 已取消
- 模型设计:
订单商品
应该包含那些字段
- 订单号: order
- 商品信息模型: sku
- 购买的商品数量: count
- 购买的商品单价: price
- 其他可选字段
- 评价: comment
- 评分: score
- 是否匿名: is_anonymous
- 是否评价了: is_commented
提交订单
页面分析
-
展示三块数据
-
收货地址(可选,之前的接口已写好)
-
支付方式(可选: 货到付款/支付宝,用户自己选择)
-
商品列表(不可修改,后端要做的事情就是这个[包含运费字段])
-
-
接口行为: 属于完全从
db
获取数据的行为,所以,序列化器不作校验(views
只作用户认证) -
构造的数据格式(使用两个序列化器搞定)
{
"freight":"100.00", # 订单序列化器
"skus":[ # sku序列化器
{
......
},
{
......
},
]
}
redis
存储的数据格式如下
- hash: cart_user_id
{
'sku_id_1':count1,
'sku_id_2':count2,
'sku_id_3':count3,
}
- set:
(sku_id_1,sku_id_2,sku_id_3)
- 收集数据思路:
- 获取redis该用户的所有购物车数据
- 根据sku_id获取 sku_queryset数据集
- 遍历sku_queryset数据集,为每个 sku_obj新增count属性并赋值
- 手动构造最终的数据集,交给'序列化器'序列化,返回给前端
{
'freight':freight,
'skus':skus_queryset
}
生成订单
页面分析
- 接口行为:
post
,db
需新增一条订单信息
记录()和订单商品
记录订单信息
记录: 返回给前端 订单号 和 订单总金额订单商品
记录: 用户点击我的订单
渲染数据
- 订单号: order_id (加入时间戳,请求来了就自动生成)
- 下单用户: user(request取)
- 下单用户收货地址: address(前端传)
- 商品总数: total_count(先设置一个假数据,比如为0,后续统计sku再取数据)
- 商品总价: total_amount(先设置一个假数据,比如为0,后续统计sku再取数据)
- 运费: freight(随意)
- 支付方式(本项目两种): pay_method(前端传)
- 支付宝
- 货到付款
- 订单状态(6种): status(如果是支付宝,就显示 待支付;其他显示 待发货)
- 待支付
- 待发货
- 待收货
- 待评价
- 已完成
- 已取消
序列化器
分析:
- 前端传了两个字段 address && pay_method 所以序列化器需校验(write_only)
- 还需要返回 order_id(read_only)
- 重写 create()方法来实现新增db的行为
create()
方法分析: 主要涉及到sku
的库存问题,当库存不足的时候,不能为用户生成订单,又涉及到事务
以及并发资源抢夺(锁)
的问题
- 根据前端传过来的字段,生成 订单信息记录(total_amount和total_count先用假数据代替)
- 更新sku库存和销量
- 从redis 购物车数据取sku_id和count,根据sku_id遍历sku模型
- 取出的count和sku.stock进行对比
- count比较多就引发'库存'问题
- connt正常的话,就更新sku.stock && sku.sales
- 生成订单商品记录: order,sku,count,price
- 累加订单信息的 total_amount && total_count
- total_amount 加上 freight运费,再次保存订单信息对象并返回该对象
-
事务
的运用:上述操作,同时操作了三张表OrderInfo
&&OrderGoods
&&SKU
当触发
库存不足
异常的时候,三表应该共同进退
- 从生成 OrderInfo的上方,创建事务还原点
- 触发 库存不足 就回滚还原点
- 没触发异常就 提交事务
-
乐观锁
解决资源抢夺
的问题: 在更新库存
以及销量
的时候,我们先查一遍,目前的库存是否和之前一样- 若库存一样,就更新库存和销量
- 若不一样,就退回到更新之前的操作(让用户拥有无线下单的机会)
- 虽然资源抢夺失败,但若库存仍充足的话,允许用户继续之前的下单流程(while...continue...break)
- 抢夺失败就continue
- 正常就继续下单流程,最后break,退出循环
- 虽然资源抢夺失败,但若库存仍充足的话,允许用户继续之前的下单流程(while...continue...break)
-
MySQL
事务隔离级别
- 修改MySQL配置文件 'my.ini': transaction-isolation=READ-COMMITTED
- 最后,清空用户的redis购物车数据