订单页面

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

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

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

template:

 <el-col :span="" 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:

 <template>
<div class="cart">
<Header/>
<div class="cart-info">
<h3 class="cart-top">购物车结算 <span>共1门课程</span></h3>
<div class="cart-title">
<el-row>
<el-col :span="2">&nbsp;</el-col>
<el-col :span="10">课程</el-col>
<el-col :span="8">有效期</el-col>
<el-col :span="4">价格</el-col>
</el-row>
</div>
<div class="cart-item" v-for="item in course_list" >
<el-row>
<el-col :span="2" class="checkbox">&nbsp;&nbsp;</el-col>
<el-col :span="10" class="course-info">
<img :src="item.course.course_http_img" alt="">
<span>{{item.course.name}}</span>
</el-col>
<el-col :span="8"><span>永久有效</span></el-col>
<el-col :span="4" class="course-price">¥{{item.unit_price}}</el-col>
</el-row>
</div>
<div class="calc">
<el-row class="pay-row">
<el-col :span="4" class="pay-col"><span class="pay-text">支付方式:</span></el-col>
<el-col :span="4"><span class="alipay"><img src="../../static/images/1554167287107.png" alt=""></span></el-col>
<el-col :span="12" class="count">实付款: <span>¥{{total}}</span></el-col>
<el-col :span="4" class="cart-pay"><span >支付宝支付</span></el-col>
</el-row>
</div>
</div>
<Footer/>
</div>
</template> <script>
import Header from "./common/Header"
import Footer from "./common/Footer" export default {
name:"Order",
data(){
return {
total:0,
course_list:[],
token: localStorage.token || sessionStorage.token,
id : localStorage.id || sessionStorage.id,
order_id:sessionStorage.order_id || null,
}
}, components:{
Header,
Footer, },
methods:{ },
created() {
// 判断用户是否已经登陆了。
if( !this.token){
this.$router.push("/login");
} let _this = this;
// 发起请求获取购物车中的商品信息
_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 })
},
}
</script> <style scoped>
.cart{
margin-top: 80px;
}
.cart-info{
overflow: hidden;
width: 1200px;
margin: auto;
}
.cart-top{
font-size: 18px;
color: #666;
margin: 25px 0;
font-weight: normal;
}
.cart-top span{
font-size: 12px;
color: #d0d0d0;
display: inline-block;
}
.cart-title{
background: #F7F7F7;
height: 70px;
}
.calc{
margin-top: 25px;
margin-bottom: 40px;
} .calc .count{
text-align: right;
margin-right: 10px;
vertical-align: middle;
}
.calc .count span{
font-size: 36px;
color: #333;
}
.calc .cart-pay{
margin-top: 5px;
width: 110px;
height: 38px;
outline: none;
border: none;
color: #fff;
line-height: 38px;
background: #ffc210;
border-radius: 4px;
font-size: 16px;
text-align: center;
cursor: pointer;
}
.cart-item{
height: 120px;
line-height: 120px;
}
.course-info img{
width: 175px;
height: 115px;
margin-right: 35px;
vertical-align: middle;
}
.alipay{
display: block;
height: 48px;
}
.alipay img{
height: 100%;
width:auto;
} .pay-text{
display: block;
text-align: right;
height: 100%;
line-height: 100%;
vertical-align: middle;
margin-top: 20px;
}
</style>

order.views:

 import random
from datetime import datetime
from decimal import Decimal
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView from luffy.apps.orders.models import Order, OrderDetail
from luffy.apps.orders.serializers import OrderSerializer class OrderAPIView(APIView):
def get(self,request):
# 获取用户ID
user_id = request.user.id return Response({"message":"ok"})
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) 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)

order/serializer:

 from rest_framework import serializers

 from luffy.apps.courses.models import Course
from luffy.apps.orders.models import Order, OrderDetail class CourseDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields=("course_http_img","name") class OrderDetailSerializer(serializers.ModelSerializer):
course = CourseDetailSerializer()
class Meta:
model = OrderDetail
fields=("unit_price","course") class OrderSerializer(serializers.ModelSerializer):
order_course = OrderDetailSerializer(many=True)
class Meta:
model = Order
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. Spring MVC原理及配置详解

    Spring MVC概述: Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单.这些控制 ...

  2. bounds的应用

    frame是参考父view的坐标系来设置自己左上角的位置.设置bounds可以修改自己坐标系的原点位置,进而影响到其“子view”的显示位置.   向上滚动scrollview,我们就不断增加scro ...

  3. 自动化部署iptables防火墙脚本

    #!/bin/sh # Remove any existing rules # 清除规则 /sbin/iptables -F # 清除用户自定义规则 /sbin/iptables -X # 清除链的计 ...

  4. [LeetCode] 90.Subsets II tag: backtracking

    Given a collection of integers that might contain duplicates, nums, return all possible subsets (the ...

  5. hive 基础

    Apache的顶级项目,(java) 2008年Facebook公司开源给Apache基金会 官网:http://hive.apache.org/ hive 将SQL转换成MapReduce程序,并将 ...

  6. One VS Rest

    简单来说就是分类的类别有多个,不再是二分,比如根据某些特征,什么温度.湿度.空气流动情况来预测天气,天气的label不能说是好天气和坏天气两种,而是分晴天.雨天.阴天,雪天等等,对于决策树或者从计算机 ...

  7. kendo treeview checkbox初始化选中问题,没解决,暂时记录下

    想做带有checkbox的tree,由于项目一直用kendo ui for mvc,感觉 牛逼的kendo肯定有tree.结果碰到了选中的问题. 无法根据后台传来的IsChecked字段来设置  tr ...

  8. 4.Python3运算符

    4.1算数运算符(以下假设变量a为10,变量b为21) 实例操作: print(3 + 5) #数字3与5相加 print(3 - 5) #数字3与5相减 print(3 * 5) #数字3与5相乘 ...

  9. Centos7 Yum安装 PHP5.5,5.6,7.0

    默认的版本太低了,手动安装有一些麻烦,想采用Yum安装的可以使用下面的方案: 1.检查当前安装的PHP包 yum list installed | grep php 如果有安装的PHP包,先删除他们 ...

  10. spring 获取对象的注解

    BeanDefinition definition = registry.getBeanDefinition(name); if (definition instanceof AnnotatedBea ...