• 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    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      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      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   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
  • 相关阅读:
    jquery swiper自定义pagination的方法
    javascript获取地址栏参数的方法
    jquery trigger使用方法
    jquery on绑定事件叠加解决方法
    phpexcel无法导出的解决方法
    mysql left join和union结合的用法
    Linux项目一
    排序
    搜索
    递归
  • 原文地址:https://www.cnblogs.com/Mixtea/p/10639614.html
Copyright © 2020-2023  润新知