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

本文详细介绍了如何在Django中创建订单模型,包括订单信息和订单商品,涉及字段定义、枚举常量、数据库迁移以及订单状态管理。同时展示了订单页面数据的获取逻辑,包括用户收货地址、购物车商品信息和运费的处理。最后,阐述了订单提交的完整流程,包括事务处理、库存管理以及购物车商品的同步。整个过程涵盖了从数据模型设计到业务逻辑实现的关键步骤。

创建订单模型类

models.py

from django.db import models

# Create your models here.
from django.db import models

from apps.goods.models import SKU
from apps.users.models import User, Address
from utils.models import BaseModel


class 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_id


class 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位  左边补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):
        # 获取到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})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值