zoukankan      html  css  js  c++  java
  • pythondjango框架电商项目订单模块开发_20191125

    python-django框架-电商项目-订单模块开发

    提交订单页面:

    • 在购物车中点击提交订单,就应该到达提交订单页面了,
    • 显示:
    • 1,收获地址,
    • 2,支付方式
    • 3,用户购买的商品信息,数量,小计,
    • 4,总金额,运费,实际付多少,
    • 5,提交订单按钮,
    • 点击提交按钮,需要传递什么?
    • 注意:价格这个是给用户看的,不要传到后台,传了后端也不用,
    • 商品的id要传过去,另外商品的数量,我们也是从redis中拿的,不是页面上的
    • 我们可以把要传的信息放入一个表单,
    • 表单中的checkbox,只有被选中时,值才会被提交,
    • 后端增加一个提交订单的视图,
    • 1,接收数据,
    • 2,遍历用户购买的商品信息,
    • 总的数量,总的价格,
    • 运费,实际开发的时候,是一个子系统,现在我们把这个写死,
    • 实际支付,就是总价格+运费,
    • 获取用户的地址,只要是这个用户的,我们就从数据库查出来,注意页面流出来编辑收获地址的按钮,
    • 组织上下文,
    • 注意:没有登陆的时候是不能进入这个页面的,跳转到登陆页面,

    创建订单前端js:

    • 订单相关的有两张表,订单信息表,订单商品表,
    • 前端的订单提交页面,我们点击提交订单,应该提交哪些数据???
    • 商品的id,商品的运费,商品的收获地址,支付方式,
    • 至于总件数,总金额,这些传了也不会用,
    • 点击提交的时候,使用的是ajax请求,

     创建订单后端的操作

    • 前端有了js提交之后,我们后端就可以去接收这个请求了,
    • 创建订单的核心业务,
    • 1,用户下一个订单,我要往订单信息表中加入一条信息,这个时候的总数量和总金额,都是0,支付编号不用管,有默认值,订单状态一开始都是未支付,
    • 2,往订单商品表中加入多条记录,评论刚刚下订单是没有的,默认是空,
    • 3,下单成功了之后还需要更新商品的库存信息,因为之前都是0
    • 4,把购物车中的商品清除,  
    • 5,返回一个应答,下单成功, 

    订单生成-mysql的事物的概念:

    • 如果一共两个库存,但是两个用户都加了两个商品,一个客户先买了,第二个客户再次去购买,库存就是零了,这个时候怎么办?
    • 我们需要在生成订单的时候判断库存,如果大于库存,我们应该返回商品库存不足,
    • 所以整个创建订单的流程,需要做成一个事务,
    • 什么是mysql事务,要么全都执行,要么全部执行,
    • 特点:
    • 1,原子性,一组事务,要么成功,要么撤回
    • 2,稳定性,如果有非法的数据,可以撤回,
    • 3,事务的隔离性,一个事务的处理结果,如果影响了其他的事物,其他的也会撤回
    • 4,可靠性,事务会保存到日志里面,软硬件崩溃了,恢复之后可以做一个重新执行
    • mysql中事务控制的语句,
    • 1,开启事务, begin; # 开始事务,后面写的语句都是在事务里面,
    • 2,事务的提交 ,commit; # 提交事务
    • 3,事务的回滚,rollback; # 回滚,提交和回滚是事务的两个操作,
    • 还可以创建保存点,叫做标记点,
    • 设置保持点的命令:
    • SAVEPOINT savepoint_name; // 声明一个 savepoint
    • ROLLBACK TO savepoint_name; // 回滚到savepoint,这个点之前的没有回滚,之后的回滚了,
    • RELEASE SAVEPOINT savepoint_name;  // 删除指定保留点
    • 一旦开始了一个事务,
    • 要么是提交了,要么是回滚,才是结束,否则都不是结束,
    • 事务中可以设置保存点,

    django中使用事务,

    • 怎么把django中的是一系列操作放入一个事务里面呢?
    • 我们需要一个django的模块:from django.db import transaction
    • 然后使用    @transaction.atomic,这个装饰器,装饰我们的函数,
    • 把涉及到的数据库操作放入一个事务里面,
    • 你只要一装饰,这个函数就是一个事务,
    • 什么时候使用保存点呢?
    • 对数据库的操作分为两段,我们把核心也为设置一个保存点,
    • # 设置事务保存点,,save_id = transaction.savepoint()
    • # 商品不存在需要回滚,transaction.savepoint_rollback(save_id)
    • # 提交事务,否则不会提交,,transaction.savepoint_commit(save_id)

    订单生成-订单兵法的问题:

    • 举例:用户1要买一个鸡腿,这个鸡腿只有一个了,这是一个进程,
    • 1,要往数据库中添加一条记录, 
    • 2,查询商品鸡腿的信息,然后紧接着往订单商品表加入数据之前,我们进行一个库存的判断,
    • 3,判断没有问题,添加记录,
    • 4,进行商品库存的更新,
    • 如果在用户1买的时候,又有一个人去买了这个鸡腿,这是第二个进程,
    • 然后也执行这个函数,
    • 这两个进程是没有关系的,
    • 多于多进程多线程的时候,调哪一个进程是随机,
    • 假设先调的进程1,判断库存的时候假设是可以的,
    • 现在我们的电脑切换进程了,切换到了用户2,这个时候查询库存也是够的,
    • cpu再次进行切换,换进程1,那就更新库存为0 了
    • cpu再次进行切换,换进程2,去更新库存,这个时候你就会发现只有一个鸡腿,但是你卖出了两份,
    • 什么时候会发生, 就是大量的用户买一个商品的时候,比如秒杀,比如iPhone,比如小米,这时候就会有订单并发的问题,

    订单并发的处理:悲观锁,

    • 卖出的量超过了库存,这种并发问题怎么解决,
    • 有两种解决方法
    • 1,悲观锁,
    • 2,乐观锁。
    • 首先第一种悲观锁,什么是悲观锁,这个就是对应进程中锁的概念,谁拿到锁谁就可以去改,没有拿到的不能改,
    • 悲观锁就是这样,这个里面查询商品的时候我加一个锁,我拿到这个记录就把这条记录锁定,别的进程就拿不到了,拿不到就要等待,拿到了才可以处理,
    • 事务提交或者事务回滚的时候,也就是事务结束的时候,就会把这个锁释放,
    • 这样悲观锁就解决了这个问题,
    • 怎么加锁?
    • 就是查询的时候,加一个for update,
    • select * from df_goods_sku where id=sku_id for update;
    • 在django中怎么去写?
    • sku = GoodsSKU.objects.select_for_update().get(id=sku_id)
    • 在事务中可以写保存点:
    • # 设置事务保存点
    • save_id = transaction.savepoint()
    • transaction.savepoint_rollback(save_id)
    • # 提交事务,否则不会提交
    • transaction.savepoint_commit(save_id)

     订单并发-乐观锁:

    • 在查询数据的时候不加锁,在更新时进行判断,
    • 判断更新时的库存和之前的查出的库存是否一致,
    • 也就是说,我查到的库存是1,我更新的时候库存也是1,那就是没有人对这条数据操作,我就可以操作这个数据了,
    • # 返回受影响的行数,表示1更新成功,返回0表示更新失败
    • res = GoodsSKU.objects.filter(id=sku_id, stock=orgin_stock) .update(stock=new_stock, sales=new_sales)
    • 根据这个条件查询,更新,要么是1,要么是0,1就是更新成功了,
    • 更新失败了,要回滚
    • 更新失败,说明确实之前被人改了,但是我还是尝试3次,再加一个for循环,
    • #######
    • 模拟两个用户操作同一个商品,使用悲观锁,
    • 1,两个都提交,都是第一次循环,
    • 2,第一个人提交了之后,查出来还是库存没有变这是怎么回事
    • 这是因为事务的隔离性,
    • 有四个隔离级别:
    • 1,读取未提交的内容,
    • 假设有两个事务,A和B,我在事务A中执行了插入语句,但是我还没有提交,但是这个隔离级别,事务B就可以查到事务A为提交的插入语句的内容改变,
    • 这是脏读,dirty read,这是读取未提交的内容,
    • 2,读取提交的内容,
    • 假设有两个事务,A和B,我在事务A中执行了插入语句,但是我还没有提交,这个时候事务B是拿不到内容的,只有事务A提交了,事务B才可以查看到,这是大多数数据库的默认隔离级别,但是不是mysql的
    • 3,可重复读,
    • 这是mysql的默认的隔离级别,假设有两个事务,A和B,我在事务A中执行了插入语句,但是我还没有提交,这个隔离级别,即使你提交了,我还是不拿你提交后的,还是拿到事务A更新之前的,这就是可重复读,
    • 这种会出现的问题就是幻读,在一个事务的两次查询中数据笔数不一致,什么意思?就是数据的列数不一致,
    • 举例:一个事务查询了3列数据,而另一个事务却在此时插入了几条新的数据,先前的事务在接下来的查询中,就会发现有几列数据是我之前没有查到的,这就是幻读,
    • 4,可串行化
    • 这是最高级别的隔离,强制事务进行排序,使事务之间不可能之间相互冲突,从而解决幻读的问题,但是会导致大量的超时现象和锁的竞争,处理效率低
    • ############
    • 之前我们出现的就是因为mysql默认是可重复读,这种我们拿不到上一个事务更新之后的库存,导致我更新是失败的,所以我们要更改mysql的事物隔离级别,改为读取提交的内容,
    • 怎么设置?
    • 找到mysql的日志文件,sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
    •  transaction-isolation = READ-COMMITTED
    • 重启mysql的服务,sudo service mysql restart
    • 这样就可以了,

    订单并发-总结:

    • 在冲突比较少的时候,建议使用乐观锁,我没有加锁,没有释放锁,就减少了开销,提交性能,
    • 冲突比较多的时候,使用悲观锁
    • 乐观锁重复操作的代价比较大,也使用悲观锁,

    用户中心-订单页面:

    • 提交订单页面,点击提交订单之后,提交成功,会进入用户中心的订单查看页面,
    • 用户中心有一个单独的用户中心订单页面,
    • 后端需要一个视图,用来返回订单的信息,
    • 我们在用户中心的订单页面,看到之前下的但是待支付的状态,点击去支付我们就可以支付了,
    • 点击支付会跳转到支付宝的二维码页面,然后登陆就可以支付了,
    • 需要研究一下支付宝支付的内容,

    订单支付代码:

    • 点击订单列表页面,点击去付款,采用post请求,给django网站传递参数,
    • 我们需要给支付宝传参数,我们要使用一个sdk,这样就不用我们自己传参数了,
    • 安装这个包,https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
    • 先卸载一个包:pip uninstall pycrypto
    • 然后安装:pip install python-alipay-sdk --upgrade
    • 安装好了之后,你就有这个包了,你就可以使用了,
    • ########
    • 先搞清楚支付宝的沙箱环境,
    • 进入支付宝点开放平台网站,https://open.alipay.com/
    • 击“开放平台-开发者中心-沙箱环境”。进入沙箱环境页面,系统已经自动为你创建一个应用,在 信息配置 中可以看到应用信息。
    • 二.生成密钥文件
    • 1. 使用OpenSSL
    • openssl
    • 2. 生成私钥
    • genrsa -out app_private_key.pem 2048
    • 3. 生成公钥
    • rsa -in app_private_key.pem -pubout -out app_public_key.pem
    • 4. 退出OpenSSL
    • exit
    • ###########
    • 有了自己的公钥和私钥了,下一步就是要配置,在支付宝的沙箱环境,设置自己的公钥,支付宝就会反复支付宝的公钥,
    • 这个支付宝的公钥,是我们接收到支付宝的内容之后进行解密的,
    • 所以我们要把这个支付宝的公钥保存到我们的项目里面,
    • 我们在order应用下面,把支付宝的公钥,和我们私钥都放到这个文件夹下, 
    • 这样就配置玩了,
    • ##################
    • 怎么使用?
    • 前端点击支付的时候使用ajax+post请求,
    • 需要传递的参数:order_id,
    • 后端查看这个订单,有几个查询条件,订单号带上,是这个用户的,是支付宝支付方式,是待支付的状态的,能查到就是一个有效的订单,
    • 没有问题下一步就开始调用支付宝的接口了,
    • 1,初始化
    • 2,调接口,
    • 3,返回应答,这里就是方法pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string
    • 报错:    raise ValueError("RSA key format is not supported")
    • 把接入支付宝的时候的参数改为:app_private_key_string----->  app_private_key_path
    • 报错:    raise ValueError("Not a valid PEM pre boundary")
    • 原来是我的前后的标记多谢了横杠,两边只能是五个,我写了7个,-----END RSA PRIVATE KEY-----注意这个标记的两边必须要是5个,不是5个就会报这个错,
    • 现在通了,
    • 现在登录沙箱环境,查看沙箱账号,买家账号密码

    订单支付-获取支付结果:

    • 因为我们现在不是公网环境,所以支付宝不能返回给我们支付结果,
    • 所以我们自己去查询交易的结果,
    • 获取了支付宝的交易结果之后,给用户一个支付的结果,支付成功,或者失败,
    • 用户浏览器访问我们的网站,然后看支付是否成功,
    • 用户的浏览器什么时候访问我们的地址,
    • 怎么设计??
    • 我们把用户引导到支付页面之后,
    • 检查支付状态,支付成功了,
    • 弹出支付成功,然后刷新页面,把数据库里面的订单状态改掉,

    订单评论:

    • 前端有单独的评论的页面,
    • 一个订单有多个商品,应该有多个评论框,
    • 评论之后提交,订单的状态从去评价变为完成,
    • 在商品详情页面就有一个评价,应该要显示评价, 
  • 相关阅读:
    Atitit fms Strait (海峡) lst 数据列表目录1. 4大洋 12. 著名的海大约40个,总共约55个海 13. 海区列表 23.1. 、波利尼西亚(Polynesia,
    Atitit trave islands list 旅游资源列表岛屿目录1. 东南亚著名的旅游岛屿 21.1. Cjkv 日韩 冲绳 琉球 济州岛 北海道 21.2. 中国 涠洲岛 南澳
    Atitit Major island groups and archipelagos 主要的岛群和群岛目录资料目录1. 岛群 波利尼西亚(Polynesia, 美拉尼西亚(Melanesia,
    Atitit glb 3tie city lst 三线城市列表 数据目录1. 全球范围内约90个城市 三线 12. 世界性三线城市全球共
    Atitit glb 1tie 2tie city lst 一二线城市列表数据约50个一线城市Alpha ++ 阿尔法++,,London 伦敦,,New York 纽约,,Alpha +
    Attit 现代编程语言重要特性目录第一章 类型系统 基本三大类型 2第一节 字符串 数字 bool 2第二节 推断局部变量 2第三节 动态类型 2第二章 可读性与开发效率 简单性 2
    Atitit 未来数据库新特性展望目录1. 统一的翻页 21.1. 2 Easy Top-N
    使用Chrome DevTools(console ande elements panel)进行xpath/css/js定位
    chrome -console妙用之定位xpath/js/css
    表达式树之构建Lambda表达式
  • 原文地址:https://www.cnblogs.com/andy0816/p/11928105.html
Copyright © 2011-2022 走看看