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

订单页面

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

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

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

template:

 <el-col :span="3" class="cart-calc"><span @click="create_order">去结算</span></el-col>

script,methods中:
create_order(){
          // 生成订单
        this.$axios.post("http://127.0.0.1:8000/orders/",{},{
          headers: {
            // 附带已经登录用户的jwt token 提供给后端,一定不能疏忽这个空格
            'Authorization': 'JWT ' + this.token
          },
          responseType: "json",
        }).then(response=>{
          //在session中保存订单ID,便于在结算页面发送请求时带上order_id,查询订单详情
         sessionStorage.order_id = response.data.order_id;

          // 跳转到结算页面
          this.$router.push("/order")

        }).catch(error=>{
          // 生成订单失败
          alert("生成订单失败")
        })

 

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

order.models:

订单的模型:

# Create your models here.
from django.db import models

# Create your models here.
from luffy.apps.user.models import User
from luffy.apps.courses.models import Course
class Order(models.Model):
    """订单记录"""
    status_choices = (
        (0, '未支付'),
        (1, '已支付'),
        (2, '已取消'),
    )
    total_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="订单总价", default=0)
    order_number = models.CharField(max_length=32,verbose_name="订单号")
    order_status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="订单状态")
    order_desc = models.CharField(max_length=120,verbose_name="订单描述")
    created_time = models.DateTimeField(verbose_name="订单生成时间", auto_now_add=True)
    pay_time = models.DateTimeField(verbose_name="订单支付时间", auto_now_add=True)
    user = models.ForeignKey(User, related_name='user_orders', on_delete=models.DO_NOTHING,verbose_name="用户ID")
    class Meta:
        db_table="ly_order"
        verbose_name= "订单记录"
        verbose_name_plural= "订单记录"


class OrderDetail(models.Model):
    """订单详情"""
    order = models.ForeignKey("Order", related_name='order_course', on_delete=models.CASCADE, verbose_name="订单ID")
    course = models.ForeignKey(Course, related_name='course_order', on_delete=models.CASCADE, verbose_name="课程ID")
    user = models.ForeignKey(User, null=True, related_name="course", on_delete=models.DO_NOTHING, verbose_name="用户ID")
    unit_price = models.DecimalField(max_digits=8, decimal_places=2, null=True, verbose_name="课程价格")

    class Meta:
        db_table="ly_order_detail"
        verbose_name= "订单详情"
        verbose_name_plural= "订单详情"

 

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

class OrderAPIView(APIView):
   
    def post(self,request):
        # 获取用户ID
        try:
            user_id = request.user.id
        except:
            return Response({"message": "用户不存在!"})

        # 自己生成一个订单号,# 结合时间戳和当前用户ID来生成,才能保证整站唯一
        order_number = datetime.now().strftime("%Y%m%d%H%M%S") + "%07d" % int(user_id) + "%04d" % random.randint(0,9999)
        # 从redis中获取商品信息[先获取勾选集,然后根据勾选集,到购物车中查询对应的商品价格]
        redis = get_redis_connection("cart")
        course_id_list = redis.smembers("cart_select_%s" % user_id)
        # 计算总价格
        total_price = 0
        cart_info = redis.hgetall("cart_%s" % user_id) # 返回哈希数据中的键值对
        for course_id,course_price in cart_info.items():
            if course_id in course_id_list:
                total_price += Decimal(course_price.decode())
        # 创建订单数据
        order = Order.objects.create(
            user_id = user_id,
            order_number = order_number,
            order_status = 0,  # 订单状态默认为未支付
            order_desc = "路飞学成课程购买",  # # 订单描述信息
            total_price = total_price
        )
        # 返回响应信息给客户端
        print("order",order)
        print("order_type", type(order))
        if order:
            for course_id in course_id_list:
                # 记录订单相关的课程信息到订单详情
                OrderDetail.objects.create(
                    course_id = course_id,
                    order_id = order.id,
                    user_id = user_id,
                    unit_price = redis.hget("cart_%s" % user_id, course_id).decode(),
                )
                # 删除redis中已经生成订单的商品信息
                redis.hdel("cart_%s" % user_id, course_id.decode())
                redis.srem("cart_select_%s" % user_id, course_id.decode())

            return Response({"order_id": order.id}, status=status.HTTP_200_OK)
        else:
            return Response({"message": "生成订单失败!"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

 

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

 created() {
       // 判断用户是否已经登陆了。
      if( !this.token){
        this.$router.push("/login");
      }

       let _this = this;
      // 发起请求获取购物车中的商品信息,_this.order_id时在cart发送创建订单请求返回数据时,保存在session中的订单ID
      _this.$axios.get("http://127.0.0.1:8000/orders/detail/"+_this.order_id,{
          headers: {
              'Authorization': 'JWT ' + _this.token
          },
          responseType: 'json',
        }).then(response=>{
          console.log("response.data",response.data)
          _this.course_list = response.data.order_course;
          _this.total = response.data.total_price

        })

 

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

order/views

class OrderDetailAPIView(APIView):
    def get(self,request,order_id):
        """显示订单中的商品信息"""
        try:
            order = Order.objects.get(pk=order_id)
        except Order.DoesNotExist():
            return Response({"message":"当前订单不存在!"},status=status.HTTP_400_BAD_REQUEST)

        seriazlier = OrderSerializer(instance=order)
        return  Response(seriazlier.data,status=status.HTTP_200_OK)

 

其中使用了序列化器:

from rest_framework import serializers

from .models import Order,OrderDetail
from courses.models import Course
class CourseSerializer(serializers.ModelSerializer):
    class Meta:
        model = Course
        fields = ("course_http_img","name")

class OrderDetailSerializer(serializers.ModelSerializer):
    course = CourseSerializer()
    class Meta:
        model = OrderDetail
        fields = ("course","unit_price")

class OrderSerializer(serializers.ModelSerializer):
    order_course = OrderDetailSerializer(many=True)
    class Meta:
        model= Order
        fields = ("id","total_price","order_course")

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

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

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

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

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

courses/models:

class Course(models.Model):
    .....
    
       
  # 自定义显示字段
    def course_http_img(self):
        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 
 86 <style scoped>
 87 .cart{
 88   margin-top: 80px;
 89 }
 90 .cart-info{
 91   overflow: hidden;
 92   width: 1200px;
 93   margin: auto;
 94 }
 95 .cart-top{
 96   font-size: 18px;
 97   color: #666;
 98   margin: 25px 0;
 99   font-weight: normal;
100 }
101 .cart-top span{
102     font-size: 12px;
103     color: #d0d0d0;
104     display: inline-block;
105 }
106 .cart-title{
107     background: #F7F7F7;
108     height: 70px;
109 }
110 .calc{
111   margin-top: 25px;
112   margin-bottom: 40px;
113 }
114 
115 .calc .count{
116   text-align: right;
117   margin-right: 10px;
118   vertical-align: middle;
119 }
120 .calc .count span{
121     font-size: 36px;
122     color: #333;
123 }
124 .calc .cart-pay{
125     margin-top: 5px;
126     width: 110px;
127     height: 38px;
128     outline: none;
129     border: none;
130     color: #fff;
131     line-height: 38px;
132     background: #ffc210;
133     border-radius: 4px;
134     font-size: 16px;
135     text-align: center;
136     cursor: pointer;
137 }
138 .cart-item{
139   height: 120px;
140   line-height: 120px;
141 }
142 .course-info img{
143     width: 175px;
144     height: 115px;
145     margin-right: 35px;
146     vertical-align: middle;
147 }
148 .alipay{
149   display: block;
150   height: 48px;
151 }
152 .alipay img{
153   height: 100%;
154   width:auto;
155 }
156 
157 .pay-text{
158   display: block;
159   text-align: right;
160   height: 100%;
161   line-height: 100%;
162   vertical-align: middle;
163   margin-top: 20px;
164 }
165 </style>
View Code

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

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")
View Code

 

posted @ 2019-04-02 21:19  Mixtea  阅读(922)  评论(0编辑  收藏  举报