Django项目实战----订单页面的显示和生成订单、提交订单的逻辑

article/2025/8/19 19:23:31

创建订单模型类

models.py

from django.db import models# Create your models here.
from django.db import modelsfrom apps.goods.models import SKU
from apps.users.models import User, Address
from utils.models import BaseModelclass OrderInfo(BaseModel):"""订单信息"""# 付款方式   货到付款或者阿里支付(支付宝)PAY_METHODS_ENUM = {"CASH": 1,"ALIPAY": 2}PAY_METHOD_CHOICES = ((1, "货到付款"),(2, "支付宝"),)# 订单状态ORDER_STATUS_ENUM = {"UNPAID": 1,"UNSEND": 2,"UNRECEIVED": 3,"UNCOMMENT": 4,"FINISHED": 5}ORDER_STATUS_CHOICES = ((1, "待支付"),(2, "待发货"),(3, "待收货"),(4, "待评价"),(5, "已完成"),(6, "已取消"),)order_id = models.CharField(max_length=64, primary_key=True, verbose_name="订单号")user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name="下单用户")address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name="收货地址")total_count = models.IntegerField(default=1, verbose_name="商品总数")total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")freight = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="运费")pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=1, verbose_name="支付方式")status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")class Meta:db_table = "tb_order_info"verbose_name = '订单基本信息'verbose_name_plural = verbose_namedef __str__(self):return self.order_idclass OrderGoods(BaseModel):"""订单商品"""SCORE_CHOICES = ((0, '0分'),(1, '20分'),(2, '40分'),(3, '60分'),(4, '80分'),(5, '100分'),)order = models.ForeignKey(OrderInfo, related_name='skus', on_delete=models.CASCADE, verbose_name="订单")sku = models.ForeignKey(SKU, on_delete=models.PROTECT, verbose_name="订单商品")count = models.IntegerField(default=1, verbose_name="数量")price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="单价")comment = models.TextField(default="", verbose_name="评价信息")score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name='满意度评分')is_anonymous = models.BooleanField(default=False, verbose_name='是否匿名评价')is_commented = models.BooleanField(default=False, verbose_name='是否评价了')class Meta:db_table = "tb_order_goods"verbose_name = '订单商品'verbose_name_plural = verbose_namedef __str__(self):return self.sku.name

执行命令数据库迁移

# 生成迁移文件python manage.py makemigrations# 执行迁移python manage.py migrate

订单页面的显示

流程

1. 继承LoginMixin类  检测用户是否登录
2. 获取用户对象
3. 前端需要的数据:3.1 当前用户所有的收货地址3.2 当前用户购物车选中的商品信息3.3 运费
4. 查询出当前用户的所有收货地址并组织数据
5. 连接redis查询出当前用户购物车选中的数据5.1 组织数据,redis内数据为二进制要记得转换6. 运费和返回响应

前端需要的数据格式
在这里插入图片描述

代码

class OrderSettlementView(LoginMixin, View):def get(self, request):# 获取用户对象user = request.user# 查询出当前用户的所有收货地址adds = Address.objects.filter(user=user, is_deleted=False)# 组织收货地址数据addresses_list = []for address in adds:addresses_list.append({'id': address.id,'province': address.province.name,'city': address.city.name,'district': address.district.name,'place': address.place,'receiver': address.receiver,'mobile': address.mobile,})# 连接redis  取出用户选中的购物车商品redis_conn = get_redis_connection('carts')cart_data = redis_conn.hgetall('cart_%s' % user.id)select_data = redis_conn.smembers('selected_%s' % user.id)new_cart_dict = {}for sku_id in select_data:count = cart_data[sku_id]new_cart_dict[int(sku_id)] = int(count)try:skus = SKU.objects.filter(id__in=new_cart_dict.keys())except Exception as e:print(e)return JsonResponse({'code': 400, 'errmsg': '查询失败'})# 组织商品数据sku_list = []for sku in skus:sku_list.append({'id': sku.id,'name': sku.name,'price': sku.price,'count': new_cart_dict[sku.id],'default_image_url': sku.default_image.url,})context = {'addresses': addresses_list,'skus': sku_list,'freight': Decimal('10.00')}return JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})

订单提交的逻辑

流程

1. 前端发送参数为 收货地址id 付款方式
2. 获取用户对象 和 两个参数
3. 校验参数3.1 参数是否都存在3.2 收货地址id是否真实存在3.3 付款方式是否是数据库内规定的
4. 生成订单号4.1 timezone.localtime()是django自带的时间  时区根据settings.py文件内而定4.2 格式化获取到当前的时间到毫秒4.3 加上用户的id 9位  左边补0
5. 定义一开始的商品总数量和总价为0
6. 根据付款方式确定一开始的订单状态
7. 因为涉及到订单表和一个订单内含有的商品表要使用事务,如果中途出错就要回滚操作
8. 订单存入数据库
9. 取出购物车内选中的商品 
10. 遍历商品  查询是否购买的数量大于库存   库存减去购买的数量  销量加上购买的数量
11. 保存订单商品到数据库
12. 订单总价和总数量加上每一个商品的数量和总价(数量*单价)
13. 订单总价加上运费
14. 删除购物车内生成订单的商品
15. 返回响应

需要注意:

事务:
# 开始事务
from django.db import transaction
with transaction.atomic():# 设置回滚点save_id = transaction.savepoint()# 出现错误返回操作到回滚点transaction.savepoint_rollback(save_id)# 提交事务transaction.savepoint_commit(save_id)
生成订单:

格式化时间 : %Y年%m月%d日%H时%M分%S秒%f毫秒
格式化输入九位数字左边缺少的补0: %09d
timezone.localtime():django自带的时间 时区随settings.py文件内设置的而定

# 生成订单号
order_id = timezone.localtime().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)
数据表:

订单表关联用户和收货地址 一个用户可以有多个订单 一对多

订单商品表关联订单表和商品表 一个订单可以有多个商品 一对多


代码

class CommitOrder(LoginMixin, View):def post(self, request):# 获取到useruser = request.user# 获取参数 收货地址id  付款方式json_data = json.loads(request.body)address_id = json_data.get('address_id')pay_method = json_data.get('pay_method')# 校验参数  是否都存在if not all([address_id, pay_method]):return HttpResponseBadRequest('缺少参数')# 收货地址是否存在try:Address.objects.get(id=address_id)except Exception as e:print(e)return HttpResponseBadRequest('参数错误')# 付款方式是否存在if pay_method not in {OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']}:return HttpResponseBadRequest('参数错误')# 生成订单号order_id = timezone.localtime().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)# 定义订单里面商品的总数量 和 总价钱total_count = 0total_amount = 0# 运费freight = Decimal('10.00')# 订单状态status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else \OrderInfo.ORDER_STATUS_ENUM['UNSEND']# 开始事务from django.db import transactionwith transaction.atomic():# 设置回滚点save_id = transaction.savepoint()try:# 订单存入数据库order = OrderInfo.objects.create(order_id=order_id,user_id=user.id,address_id=address_id,total_count=total_count,total_amount=total_amount,freight=freight,pay_method=pay_method,status=status)except Exception as e:print(e)# 保存失败返回回滚点transaction.savepoint_rollback(save_id)return JsonResponse({'code': 400, 'errmsg': '保存失败'})# 连接redisredis_conn = get_redis_connection('carts')# 取出购物车内选中的数据  里面数据为二进制carts_dict = redis_conn.hgetall('cart_%s' % user.id)selected_list = redis_conn.smembers('selected_%s' % user.id)# 创建新字典存放不是二进制的数据new_cart_dict = {}# 遍历选中的商品id列表for sku_id in selected_list:# 取出数量count = carts_dict[sku_id]# 存入新字典 转为intnew_cart_dict[int(sku_id)] = int(count)try:# 查询出所有商品skus = SKU.objects.filter(id__in=new_cart_dict.keys(), is_launched=True)except Exception as e:print(e)# 查询失败返回回滚点transaction.savepoint_rollback(save_id)return JsonResponse({'code': 400, 'errmsg': '查询失败'})# 遍历商品列表for sku in skus:# 算出每一个商品的数量是否大于库存count = new_cart_dict[sku.id]if count > sku.stock:# 库存不足返回到回滚点transaction.savepoint_rollback(save_id)return JsonResponse({'code': 400, 'errmsg': '库存不足'})# 库存减去购买的数量sku.stock -= count# 销量加上购买的数量sku.sales += count# 保存到数据库sku.save()try:# 保存订单商品OrderGoods.objects.create(order_id=order_id,sku=sku,count=count,price=sku.price)except Exception as e:print(e)# 保存失败返回回滚点transaction.savepoint_rollback(save_id)return JsonResponse({'code': 400, 'errmsg': '保存失败'})# 订单总数量+=每一个商品的数量  总价+=每一个商品的总价order.total_count += countorder.total_amount += count * sku.price# 总价+=运费order.total_amount += order.freight# 保存到数据库order.save()# 删除购物车里面生成了订单商品redis_conn.hdel('cart_%s' % user.id, *selected_list)redis_conn.srem('selected_%s' % user.id, *selected_list)# 提交事务transaction.savepoint_commit(save_id)# 返回响应return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})

http://chatgpt.dhexx.cn/article/unap3jn8.shtml

相关文章

购物车 -- 结算、提交订单接口开发

在购物车列表中选择对应的商品之后,点击提交生成订单的过程 流程图: 接口实现: 收货地址列表接口: 此操作的数据库实现可以通过tkMapper通过方法完成 service接口: package com.qfedu.fmmall.service;import com.…

订单操作-订单详情查询代码实现

订单详情 在order-list.jsp页面上对"详情"添加链接 <button type"button" class"btn bg-olive btn-xs" onclick"location.href${pageContext.request.contextPath}/orders/findById.do?id${orders.id}"> 详情</button>…

电商项目 - 用户订单确认及下订单操作

一、订单确认页功能流程图 1、进入登录确认页之前会&#xff0c;先进入登录拦截器 同样是使用ThreadLocal来存储用户的登录信息&#xff0c;从请求的request中获取登录信息 Component public class LoginUserInterceptor implements HandlerInterceptor {public static Threa…

解决支付订单,重复提交问题!

点击上方“朱小厮的博客”&#xff0c;选择“设为星标” 后台回复"书"&#xff0c;获取 后台回复“k8s”&#xff0c;可领取k8s资料 概述 如图是一个简化的下单流程&#xff0c;首先是提交订单&#xff0c;然后是支付。支付的话&#xff0c;一般是走支付网关&#xf…

SpringBoot解决用户重复提交订单(方式二:通过Redis实现)

文章目录 前言1、方案实践1.1、引入Redis依赖1.2、添加Redis环境配置1.3、编写获取请求唯一ID的接口&#xff0c;同时将唯一ID存入redis 1.4、编写服务验证逻辑&#xff0c;通过 aop 代理方式实现1.5、在相关的业务接口上&#xff0c;增加SubmitToken注解即可 2、小结 前言 在…

后端怎样防止重复提交订单?

点击上方关注 “终端研发部” 设为“星标”&#xff0c;和你一起掌握更多数据库知识 一般我们都是这样做的&#xff1a; 创建订单的时候&#xff0c;用订单信息计算一个哈希值&#xff0c;判断redis中是否有key&#xff0c;有则不允许重复提交&#xff0c;没有则生成一个新key&…

后端怎么防止重复提交订单

前言 接口幂等性问题&#xff0c;对于开发人员来说&#xff0c;是一个跟语言无关的公共问题。本文分享了一些解决这类问题非常实用的办法&#xff0c;绝大部分内容我在项目中实践过的&#xff0c;给有需要的小伙伴一个参考。 不知道你有没有遇到过这些场景&#xff1a; 有时…

bootstrap订单提交页面

下载地址 基于bootstrap实现的订单提交页面&#xff0c;常见的电商购物网站订单确认提交页面。 dd:

移动端-确认订单页面

项目准备 lib文件中存放外来的文件&#xff0c;就比如这个项目使用到字体图标&#xff0c;那存放的就是字体图标的文件&#xff0c;css 样式&#xff0c;images 重要的图片&#xff0c;uploads 页面随时更新的图片&#xff0c;其次就是html文件。 base.css *{margin: 0;pad…

confirm-order提交订单

目录 顶部导航条&#xff1a;复用head组件新增收货地址订单收货地址页面顶部导航条&#xff1a;复用head组件无地址地址列表新增地址 增加收货地址add_address顶部导航条&#xff1a;复用head组件地址信息表单其他组件 送达时间商店商品底部弹出消息&#xff1a;复用alertTip组…

订单。。。

一、库存扣减和订单表不一致 1、网络抖动—网速是好是坏&#xff0c;不稳定。最大延迟与最小延迟的时间差&#xff0c;如最大延迟是20毫秒&#xff0c;最小延迟为5毫秒&#xff0c;那么网络抖动就是15毫秒 2、库存数据不一致的原因&#xff1a; 1&#xff09;事务性的问题 – …

实现提交订单的功能

根据购物车中的商品名称和数量生成了结算信息&#xff0c;并可以填写收货人姓名、联系电话和收货地址&#xff0c;本任务将实现提交订单的功能。 一、创建订单页面order.jsp <% page language"java" import"java.util.*" pageEncoding"UTF-8"…

美多商城项目:结算订单与提交订单

一、结算订单 1. 结算订单逻辑分析 结算订单是从Redis购物车中查询出被勾选的商品信息进行结算并展示。 2. 结算订单接口设计和定义 1.请求方式 选项方案请求方法GET请求地址/orders/settlement/ 3. 结算订单后端逻辑实现 class OrderSettlementView(LoginRequiredMixin, Vie…

电商系统-提交订单并发处理

在多个用户同时发起对一个商品的下单请求时&#xff0c;先查询商品库存&#xff0c;再修改商品库存&#xff0c;会出现资源竞争问题&#xff0c;导致库存的最终结果出现异常。 1、并发下单问题演示 每个不同的用户在程序上&#xff0c;我们可以理解成不同的线程&#xff0c;每…

Android Studio_Toast消息提醒

Android Studio_Toast消息提醒 1、Toast是Android系统提供的一种非常简洁的消息提醒方式&#xff0c;程序中可以使用它实现将短小的消息通知给用户&#xff0c;一点时间后自动消失&#xff0c;且不占用屏幕的任何空间。 2、Toast用法其实非常简单&#xff0c;通过静态方法make…

Vue 消息提示通知的几种方式汇总

Vue 消息提示通知组件&#xff08;Message /Notification&#xff09;是我们日常开发中经常使用的组件&#xff0c;它可用作与用户交互的反馈提示&#xff0c;信息提交成功、错误、操作警告等场景使用。原生JavaScript 提供了 alert、prompt、confirm 等方法 提示框1>Messag…

java信息提醒怎么实现_jsp怎么实现消息提醒

如果你是平台级别的系统,可以考虑消息队列的中间件,例如:阿里巴巴的rocketmq,用这个来做消息订阅与分发。 如果你只是简简单单的需要提示到web(jsp)页面,可以用js定时ajax访问后台,后台来确定是否有数据更新,无论这个数据是哪来的。 推荐课程:Java教程。 这里就使用在JSP页面…

RabbitMQ真延时队列实现消息提醒功能

RabbitMQ真延时队列实现消息提醒功能 一、需求场景 用户可以制定多个计划&#xff0c;同时可给该计划设置是否需要到点提醒&#xff0c;且中途可以取消提醒或修改提醒时间。 二、需要解决的问题 学习过rabbitmq的同学们都知道&#xff0c;通过TTL死信队列可以实现延时队列的…

企业微信 消息 html,企业微信怎么设置消息提醒

企业微信是一款非常不错的办公软件&#xff0c;用户加入企业群就能实时了解企业的动态。而且大家只需设置消息提醒&#xff0c;软件就会在第一时间通知你&#xff0c;不会让你错过任何重要的消息&#xff0c;下面小编为大家带来相关的设置教程。 方法/步骤分享&#xff1a; 1、…

vue websocket 新消息提醒

概述&#xff1a; 不是当前聊天&#xff0c;有其他消息来就通过2种方式接受到提醒。在连接的上下文中判断&#xff0c;符合条件的弹框&#xff0c;显示红点&#xff0c;此处调用了element弹框组件列表点击事件&#xff0c;红点消失列表显示&#xff0c;属性中包含小红点 前提…