本文共 9877 字,大约阅读时间需要 32 分钟。
models.py
from django.db import models# Create your models here.from django.db import modelsfrom apps.goods.models import SKUfrom apps.users.models import User, Addressfrom 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_name def __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_name def __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位 左边补05. 定义一开始的商品总数量和总价为06. 根据付款方式确定一开始的订单状态7. 因为涉及到订单表和一个订单内含有的商品表要使用事务,如果中途出错就要回滚操作8. 订单存入数据库9. 取出购物车内选中的商品 10. 遍历商品 查询是否购买的数量大于库存 库存减去购买的数量 销量加上购买的数量11. 保存订单商品到数据库12. 订单总价和总数量加上每一个商品的数量和总价(数量*单价)13. 订单总价加上运费14. 删除购物车内生成订单的商品15. 返回响应
需要注意:
事务:
# 开始事务from django.db import transactionwith 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): # 获取到user user = 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 = 0 total_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 transaction with 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': '保存失败'}) # 连接redis redis_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] # 存入新字典 转为int new_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 += count order.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://iquhf.baihongyu.com/