订单页面

在前面我们已经构建了,购物车的页面,接下来到了结算页面

1.首先,在购物车页面点击去结算按钮时,我们需要做如下动作

.前端发送生成订单的请求,点击标签内触发事件 create_order

  1. template:
  2.  
  3. <el-col :span="" class="cart-calc"><span @click="create_order">去结算</span></el-col>
  4.  
  5. script,methods中:
  6. create_order(){
  7. // 生成订单
  8. this.$axios.post("http://127.0.0.1:8000/orders/",{},{
  9. headers: {
  10. // 附带已经登录用户的jwt token 提供给后端,一定不能疏忽这个空格
  11. 'Authorization': 'JWT ' + this.token
  12. },
  13. responseType: "json",
  14. }).then(response=>{
  15. //在session中保存订单ID,便于在结算页面发送请求时带上order_id,查询订单详情
  16. sessionStorage.order_id = response.data.order_id;
  17.  
  18. // 跳转到结算页面
  19. this.$router.push("/order")
  20.  
  21. }).catch(error=>{
  22. // 生成订单失败
  23. alert("生成订单失败")
  24. })

后端需要对该请求作出处理,将订单保存到mysql中,并返回对应的订单的ID值(不是订单号),但是在做订单保存之前,我们必须先创建订单的数据模型,其中模型如下所示

order.models:

订单的模型:

  1. # Create your models here.
  2. from django.db import models
  3.  
  4. # Create your models here.
  5. from luffy.apps.user.models import User
  6. from luffy.apps.courses.models import Course
  7. class Order(models.Model):
  8. """订单记录"""
  9. status_choices = (
  10. (0, '未支付'),
  11. (1, '已支付'),
  12. (2, '已取消'),
  13. )
  14. total_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="订单总价", default=0)
  15. order_number = models.CharField(max_length=32,verbose_name="订单号")
  16. order_status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="订单状态")
  17. order_desc = models.CharField(max_length=120,verbose_name="订单描述")
  18. created_time = models.DateTimeField(verbose_name="订单生成时间", auto_now_add=True)
  19. pay_time = models.DateTimeField(verbose_name="订单支付时间", auto_now_add=True)
  20. user = models.ForeignKey(User, related_name='user_orders', on_delete=models.DO_NOTHING,verbose_name="用户ID")
  21. class Meta:
  22. db_table="ly_order"
  23. verbose_name= "订单记录"
  24. verbose_name_plural= "订单记录"
  25.  
  26. class OrderDetail(models.Model):
  27. """订单详情"""
  28. order = models.ForeignKey("Order", related_name='order_course', on_delete=models.CASCADE, verbose_name="订单ID")
  29. course = models.ForeignKey(Course, related_name='course_order', on_delete=models.CASCADE, verbose_name="课程ID")
  30. user = models.ForeignKey(User, null=True, related_name="course", on_delete=models.DO_NOTHING, verbose_name="用户ID")
  31. unit_price = models.DecimalField(max_digits=8, decimal_places=2, null=True, verbose_name="课程价格")
  32.  
  33. class Meta:
  34. db_table="ly_order_detail"
  35. verbose_name= "订单详情"
  36. verbose_name_plural= "订单详情"

而后端的处理代码如下所示

  1. class OrderAPIView(APIView):
  2.  
  3. def post(self,request):
  4. # 获取用户ID
  5. try:
  6. user_id = request.user.id
  7. except:
  8. return Response({"message": "用户不存在!"})
  9.  
  10. # 自己生成一个订单号,# 结合时间戳和当前用户ID来生成,才能保证整站唯一
  11. order_number = datetime.now().strftime("%Y%m%d%H%M%S") + "%07d" % int(user_id) + "%04d" % random.randint(0,9999)
  12. # 从redis中获取商品信息[先获取勾选集,然后根据勾选集,到购物车中查询对应的商品价格]
  13. redis = get_redis_connection("cart")
  14. course_id_list = redis.smembers("cart_select_%s" % user_id)
  15. # 计算总价格
  16. total_price = 0
  17. cart_info = redis.hgetall("cart_%s" % user_id) # 返回哈希数据中的键值对
  18. for course_id,course_price in cart_info.items():
  19. if course_id in course_id_list:
  20. total_price += Decimal(course_price.decode())
  21. # 创建订单数据
  22. order = Order.objects.create(
  23. user_id = user_id,
  24. order_number = order_number,
  25. order_status = 0, # 订单状态默认为未支付
  26. order_desc = "路飞学成课程购买", # # 订单描述信息
  27. total_price = total_price
  28. )
  29. # 返回响应信息给客户端
  30. print("order",order)
  31. print("order_type", type(order))
  32. if order:
  33. for course_id in course_id_list:
  34. # 记录订单相关的课程信息到订单详情
  35. OrderDetail.objects.create(
  36. course_id = course_id,
  37. order_id = order.id,
  38. user_id = user_id,
  39. unit_price = redis.hget("cart_%s" % user_id, course_id).decode(),
  40. )
  41. # 删除redis中已经生成订单的商品信息
  42. redis.hdel("cart_%s" % user_id, course_id.decode())
  43. redis.srem("cart_select_%s" % user_id, course_id.decode())
  44.  
  45. return Response({"order_id": order.id}, status=status.HTTP_200_OK)
  46. else:
  47. return Response({"message": "生成订单失败!"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

2.在1步骤完成后,前端会跳转到order页面,在加载order页面,我们需要将order页面的数据加载过来,需要发送请求

  1. created() {
  2. // 判断用户是否已经登陆了。
  3. if( !this.token){
  4. this.$router.push("/login");
  5. }
  6.  
  7. let _this = this;
  8. // 发起请求获取购物车中的商品信息,_this.order_id时在cart发送创建订单请求返回数据时,保存在session中的订单ID
  9. _this.$axios.get("http://127.0.0.1:8000/orders/detail/"+_this.order_id,{
  10. headers: {
  11. 'Authorization': 'JWT ' + _this.token
  12. },
  13. responseType: 'json',
  14. }).then(response=>{
  15. console.log("response.data",response.data)
  16. _this.course_list = response.data.order_course;
  17. _this.total = response.data.total_price
  18.  
  19. })

当前端发送请求后,我们需要在后端作出处理来响应请求,返回对应订单的数据

order/views

  1. class OrderDetailAPIView(APIView):
  2. def get(self,request,order_id):
  3. """显示订单中的商品信息"""
  4. try:
  5. order = Order.objects.get(pk=order_id)
  6. except Order.DoesNotExist():
  7. return Response({"message":"当前订单不存在!"},status=status.HTTP_400_BAD_REQUEST)
  8.  
  9. seriazlier = OrderSerializer(instance=order)
  10. return Response(seriazlier.data,status=status.HTTP_200_OK)

其中使用了序列化器:

  1. from rest_framework import serializers
  2.  
  3. from .models import Order,OrderDetail
  4. from courses.models import Course
  5. class CourseSerializer(serializers.ModelSerializer):
  6. class Meta:
  7. model = Course
  8. fields = ("course_http_img","name")
  9.  
  10. class OrderDetailSerializer(serializers.ModelSerializer):
  11. course = CourseSerializer()
  12. class Meta:
  13. model = OrderDetail
  14. fields = ("course","unit_price")
  15.  
  16. class OrderSerializer(serializers.ModelSerializer):
  17. order_course = OrderDetailSerializer(many=True)
  18. class Meta:
  19. model= Order
  20. fields = ("id","total_price","order_course")

可以看到上面代码的序列化器中,有些字段嵌套了三层,

order_course   ==>   order_course = OrderDetailSerializer(many=True)  ==>   course = CourseSerializer()

注意:在CourseSerializer这个序列化器中,

  1. class CourseSerializer(serializers.ModelSerializer):
  2. class Meta:
  3. model = Course
  4. fields = ("course_http_img","name")

  字段 course_http_img 原本是不在模型表中的,是我们自定义的一个字段,需要在对应的models中,做出定义,如下代码

courses/models:

  1. class Course(models.Model):
  2. .....
  3.  
  4. # 自定义显示字段
  5. def course_http_img(self):
  6. return settings.HOST + self.course_img.url

3.前端接收到后端返回的数据,进行数据渲染即可

完整前后端代码如下:

order.vue:

  1. <template>
  2. <div class="cart">
  3. <Header/>
  4. <div class="cart-info">
  5. <h3 class="cart-top">购物车结算 <span>共1门课程</span></h3>
  6. <div class="cart-title">
  7. <el-row>
  8. <el-col :span="2">&nbsp;</el-col>
  9. <el-col :span="10">课程</el-col>
  10. <el-col :span="8">有效期</el-col>
  11. <el-col :span="4">价格</el-col>
  12. </el-row>
  13. </div>
  14. <div class="cart-item" v-for="item in course_list" >
  15. <el-row>
  16. <el-col :span="2" class="checkbox">&nbsp;&nbsp;</el-col>
  17. <el-col :span="10" class="course-info">
  18. <img :src="item.course.course_http_img" alt="">
  19. <span>{{item.course.name}}</span>
  20. </el-col>
  21. <el-col :span="8"><span>永久有效</span></el-col>
  22. <el-col :span="4" class="course-price">¥{{item.unit_price}}</el-col>
  23. </el-row>
  24. </div>
  25. <div class="calc">
  26. <el-row class="pay-row">
  27. <el-col :span="4" class="pay-col"><span class="pay-text">支付方式:</span></el-col>
  28. <el-col :span="4"><span class="alipay"><img src="../../static/images/1554167287107.png" alt=""></span></el-col>
  29. <el-col :span="12" class="count">实付款: <span>¥{{total}}</span></el-col>
  30. <el-col :span="4" class="cart-pay"><span >支付宝支付</span></el-col>
  31. </el-row>
  32. </div>
  33. </div>
  34. <Footer/>
  35. </div>
  36. </template>
  37.  
  38. <script>
  39. import Header from "./common/Header"
  40. import Footer from "./common/Footer"
  41.  
  42. export default {
  43. name:"Order",
  44. data(){
  45. return {
  46. total:0,
  47. course_list:[],
  48. token: localStorage.token || sessionStorage.token,
  49. id : localStorage.id || sessionStorage.id,
  50. order_id:sessionStorage.order_id || null,
  51. }
  52. },
  53.  
  54. components:{
  55. Header,
  56. Footer,
  57.  
  58. },
  59. methods:{
  60.  
  61. },
  62. created() {
  63. // 判断用户是否已经登陆了。
  64. if( !this.token){
  65. this.$router.push("/login");
  66. }
  67.  
  68. let _this = this;
  69. // 发起请求获取购物车中的商品信息
  70. _this.$axios.get("http://127.0.0.1:8000/orders/detail/"+_this.order_id,{
  71. headers: {
  72. 'Authorization': 'JWT ' + _this.token
  73. },
  74. responseType: 'json',
  75. }).then(response=>{
  76. console.log("response.data",response.data)
  77. _this.course_list = response.data.order_course;
  78. _this.total = response.data.total_price
  79.  
  80. })
  81. },
  82. }
  83. </script>
  84.  
  85. <style scoped>
  86. .cart{
  87. margin-top: 80px;
  88. }
  89. .cart-info{
  90. overflow: hidden;
  91. width: 1200px;
  92. margin: auto;
  93. }
  94. .cart-top{
  95. font-size: 18px;
  96. color: #666;
  97. margin: 25px 0;
  98. font-weight: normal;
  99. }
  100. .cart-top span{
  101. font-size: 12px;
  102. color: #d0d0d0;
  103. display: inline-block;
  104. }
  105. .cart-title{
  106. background: #F7F7F7;
  107. height: 70px;
  108. }
  109. .calc{
  110. margin-top: 25px;
  111. margin-bottom: 40px;
  112. }
  113.  
  114. .calc .count{
  115. text-align: right;
  116. margin-right: 10px;
  117. vertical-align: middle;
  118. }
  119. .calc .count span{
  120. font-size: 36px;
  121. color: #333;
  122. }
  123. .calc .cart-pay{
  124. margin-top: 5px;
  125. width: 110px;
  126. height: 38px;
  127. outline: none;
  128. border: none;
  129. color: #fff;
  130. line-height: 38px;
  131. background: #ffc210;
  132. border-radius: 4px;
  133. font-size: 16px;
  134. text-align: center;
  135. cursor: pointer;
  136. }
  137. .cart-item{
  138. height: 120px;
  139. line-height: 120px;
  140. }
  141. .course-info img{
  142. width: 175px;
  143. height: 115px;
  144. margin-right: 35px;
  145. vertical-align: middle;
  146. }
  147. .alipay{
  148. display: block;
  149. height: 48px;
  150. }
  151. .alipay img{
  152. height: 100%;
  153. width:auto;
  154. }
  155.  
  156. .pay-text{
  157. display: block;
  158. text-align: right;
  159. height: 100%;
  160. line-height: 100%;
  161. vertical-align: middle;
  162. margin-top: 20px;
  163. }
  164. </style>

order.views:

  1. import random
  2. from datetime import datetime
  3. from decimal import Decimal
  4. from django_redis import get_redis_connection
  5. from rest_framework import status
  6. from rest_framework.response import Response
  7. from rest_framework.views import APIView
  8.  
  9. from luffy.apps.orders.models import Order, OrderDetail
  10. from luffy.apps.orders.serializers import OrderSerializer
  11.  
  12. class OrderAPIView(APIView):
  13. def get(self,request):
  14. # 获取用户ID
  15. user_id = request.user.id
  16.  
  17. return Response({"message":"ok"})
  18. def post(self,request):
  19. # 获取用户ID
  20. try:
  21. user_id = request.user.id
  22. except:
  23. return Response({"message": "用户不存在!"})
  24.  
  25. # 自己生成一个订单号,# 结合时间戳和当前用户ID来生成,才能保证整站唯一
  26. order_number = datetime.now().strftime("%Y%m%d%H%M%S") + "%07d" % int(user_id) + "%04d" % random.randint(0,9999)
  27. # 从redis中获取商品信息[先获取勾选集,然后根据勾选集,到购物车中查询对应的商品价格]
  28. redis = get_redis_connection("cart")
  29. course_id_list = redis.smembers("cart_select_%s" % user_id)
  30. # 计算总价格
  31. total_price = 0
  32. cart_info = redis.hgetall("cart_%s" % user_id) # 返回哈希数据中的键值对
  33. for course_id,course_price in cart_info.items():
  34. if course_id in course_id_list:
  35. total_price += Decimal(course_price.decode())
  36. # 创建订单数据
  37. order = Order.objects.create(
  38. user_id = user_id,
  39. order_number = order_number,
  40. order_status = 0, # 订单状态默认为未支付
  41. order_desc = "路飞学成课程购买", # # 订单描述信息
  42. total_price = total_price
  43. )
  44. # 返回响应信息给客户端
  45. print("order",order)
  46. print("order_type", type(order))
  47. if order:
  48. for course_id in course_id_list:
  49. # 记录订单相关的课程信息到订单详情
  50. OrderDetail.objects.create(
  51. course_id = course_id,
  52. order_id = order.id,
  53. user_id = user_id,
  54. unit_price = redis.hget("cart_%s" % user_id, course_id).decode(),
  55. )
  56. # 删除redis中已经生成订单的商品信息
  57. redis.hdel("cart_%s" % user_id, course_id.decode())
  58. redis.srem("cart_select_%s" % user_id, course_id.decode())
  59.  
  60. return Response({"order_id": order.id}, status=status.HTTP_200_OK)
  61. else:
  62. return Response({"message": "生成订单失败!"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
  63.  
  64. class OrderDetailAPIView(APIView):
  65. def get(self,request,order_id):
  66. """显示订单中的商品信息"""
  67. try:
  68. order = Order.objects.get(pk=order_id)
  69. except Order.DoesNotExist():
  70. return Response({"message":"当前订单不存在!"},status=status.HTTP_400_BAD_REQUEST)
  71.  
  72. seriazlier = OrderSerializer(instance=order)
  73. return Response(seriazlier.data,status=status.HTTP_200_OK)

order/serializer:

  1. from rest_framework import serializers
  2.  
  3. from luffy.apps.courses.models import Course
  4. from luffy.apps.orders.models import Order, OrderDetail
  5.  
  6. class CourseDetailSerializer(serializers.ModelSerializer):
  7. class Meta:
  8. model = Course
  9. fields=("course_http_img","name")
  10.  
  11. class OrderDetailSerializer(serializers.ModelSerializer):
  12. course = CourseDetailSerializer()
  13. class Meta:
  14. model = OrderDetail
  15. fields=("unit_price","course")
  16.  
  17. class OrderSerializer(serializers.ModelSerializer):
  18. order_course = OrderDetailSerializer(many=True)
  19. class Meta:
  20. model = Order
  21. fields=("id","total_price","order_course")

Luffy之结算订单页面(订单模型表的创建,订单的生成,以及订单详情展示等)的更多相关文章

  1. Django - 模型表单(创建、更新、删除)

    urls.py # /music/alubm/add/ url(r'^album/add/$', views.AlbumCreate.as_view(), name="album-add&q ...

  2. 项目中 2个或者多个EF模型 表名称相同会导致生成的实体类 覆盖的解决方法

    场景:  2个数据库, 一个新,一个旧,  把旧的 数据库中的数据,导入到新的数据库中,  使用到了2个 EF实体模型, 新数据库 和 旧数据库中的表,有的名称是相同的 (但是结构是不同的) 旧的数据 ...

  3. day85:luffy:购物车根据有效期不同切换价格&购物车删除操作&价格结算&订单页面前戏

    目录 1.购物车有效期切换 2.根据有效期不同切换价格 3.购物车删除操作 4.价格结算 5.订单页面-初始化 1.购物车有效期切换 1.关于有效期表结构的设计 1.course/models.py ...

  4. DDD实战进阶第一波(十二):开发一般业务的大健康行业直销系统(订单上下文POCO模型)

    在本系列前面的文章中,我们主要讨论了产品上下文与经销商上下文相关的实现,大家对DDD的方法与架构已经有了初步的了解. 但是在这两个界限上下文中,业务逻辑很简单,也没有用到更多的值对象的内容.从这篇文章 ...

  5. Django电商项目---完成订单页面day5

    完成订单页面 创建订单项目 python manage.py startapp df_order manas/settings.py manas/urls.py 创建静态文件: templates/d ...

  6. day88:luffy:支付宝同步结果通知&接收异步支付结果&用户购买记录&我的订单

    目录 1.支付宝同步结果通知 2.用户购买记录表 3.接受异步支付结果 4.善后事宜 5.我的订单 1.支付宝同步结果通知 1.get请求支付宝,支付宝返回给你的参数 当用户输入用户名和密码确认支付的 ...

  7. 在Ecshop后台打印订单页面将商品按货号排序

    ECSHOP后台管理里的“打印订单" 页面里的商品排序有点乱,现在想改成按序号来排序,修改方法如下 下面是在2.7.2基础上做的修改 打开 admin/order.php  文件 找到(大约 ...

  8. django-用户中心订单页面

    提交订单页面place_order.html,创建订单成功后跳转到用户订单页面 {% block bottomfiles %} <script type="text/javascrip ...

  9. 小程序swiper实现订单页面

    小程序swiper实现订单页面 myOrder.wxml <!--pages/myorder/myorder.wxml--> <view class="swiper-tab ...

随机推荐

  1. 目标检测(七)YOLOv3: An Incremental Improvement

    项目地址 Abstract 该技术报告主要介绍了作者对 YOLOv1 的一系列改进措施(注意:不是对YOLOv2,但是借鉴了YOLOv2中的部分改进措施).虽然改进后的网络较YOLOv1大一些,但是检 ...

  2. Unable to convert MySQL date/time value to System.DateTime问题解决方案

    原因:可能是该字段(date/datetime)的值默认缺省值为:0000-00-00/0000-00-00 00:00:00,这样的数据读出来转换成System.DateTime时就会有问题: 解决 ...

  3. HttpResponse输出文件

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm3.aspx. ...

  4. 《linux就该这么学》第六节,计划任务和用户身份管理!

    课本笔记:          case条件测试语句 4.4:计划任务服务 at 设置一次性计划任务 at  时间    //设置执行的任务                              a ...

  5. 第四章 DOM节点操作

    1.什么是DOM:DOM(document object model)文档对象模型,把每一个元素看做是一个节点,然后对节点进行增删改查的操作 2.DOM的分类:(1)Core Dom:可以对html, ...

  6. fiddler学习总结--手机端(APP/微信小程序)抓包

    步骤一.手机和电脑要在同一个局域网中 步骤二.完成fiddler的基本配置,与web端抓包一样: TOOLS-->options-->connections-->1.设置端口:2.勾 ...

  7. HDU 1114

    在 ACM 能够开展之前,必须准备预算,并获得必要的财力支持.该活动的主要收入来自于 Irreversibly Bound Money (IBM).思路很简单.任何时候,某位 ACM 会员有少量的钱时 ...

  8. ArrayList 除重

    看到一段简洁的 ArrayList 除重代码: protected final <T> List<T> removeDuplicates(List<T> list) ...

  9. 20165215 2017-2018-2《Java程序设计》课程总结

    20165215 2017-2018-2<Java程序设计>课程总结 一.每周作业链接汇总 预备作业1:我期望的师生关系:令我记忆深刻的老师,期望的师生关系,本学期的学习规划. 预备作业二 ...

  10. spring 的web.xml

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java ...