博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django项目实战----订单页面的显示和生成订单、提交订单的逻辑
阅读量:2094 次
发布时间:2019-04-29

本文共 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/

你可能感兴趣的文章
SQL教程之嵌套SELECT语句
查看>>
日本語の記号の読み方
查看>>
计算机英语编程中一些单词
查看>>
JavaScript 经典例子
查看>>
判断数据的JS代码
查看>>
js按键事件说明
查看>>
AJAX 设计制作 在公司弄的 非得要做出这个养的 真晕!
查看>>
Linux 查看文件大小
查看>>
Java并发编程:线程池的使用
查看>>
redis单机及其集群的搭建
查看>>
Java多线程学习
查看>>
检查Linux服务器性能
查看>>
Java 8新的时间日期库
查看>>
Chrome开发者工具
查看>>
【LEETCODE】102-Binary Tree Level Order Traversal
查看>>
【LEETCODE】106-Construct Binary Tree from Inorder and Postorder Traversal
查看>>
【LEETCODE】202-Happy Number
查看>>
和机器学习和计算机视觉相关的数学
查看>>
十个值得一试的开源深度学习框架
查看>>
【LEETCODE】240-Search a 2D Matrix II
查看>>