zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    03_ if 练习 _ little2big
    uva 11275 3D Triangles
    uva 12296 Pieces and Discs
    uvalive 3218 Find the Border
    uvalive 2797 Monster Trap
    uvalive 4992 Jungle Outpost
    uva 2218 Triathlon
    uvalive 3890 Most Distant Point from the Sea
    uvalive 4728 Squares
    uva 10256 The Great Divide
  • 原文地址:https://www.cnblogs.com/Mixtea/p/10639614.html
Copyright © 2011-2022 走看看