创建订单模型类
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})