You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django订单与订单状态建模优化:如何安全获取状态实例?

优化Django订单状态模型的方案

要解决依赖ID或显示文本获取状态实例的问题,核心思路是给OrderStatus模型添加一个不随显示内容/多语言变化的内部唯一标识,并通过模型常量和封装方法安全获取实例,具体实现如下:

1. 修改OrderStatus模型

添加语义化的slug字段作为内部唯一标识,同时定义对应状态的常量,并封装获取实例的方法(或自定义模型管理器):

方案A:使用类方法直接获取

from django.db import models

class OrderStatus(models.Model):
    # 定义内部标识常量,硬编码仅在这里出现
    STATUS_NEW_SLUG = "new"
    STATUS_IN_PROGRESS_SLUG = "in_progress"
    STATUS_FINISHED_SLUG = "finished"

    status = models.CharField(max_length=20, verbose_name="状态显示名")
    slug = models.SlugField(max_length=20, unique=True, verbose_name="内部唯一标识")

    @classmethod
    def get_new(cls):
        """获取「新建」状态实例"""
        return cls.objects.get(slug=cls.STATUS_NEW_SLUG)
    
    @classmethod
    def get_in_progress(cls):
        """获取「处理中」状态实例"""
        return cls.objects.get(slug=cls.STATUS_IN_PROGRESS_SLUG)
    
    @classmethod
    def get_finished(cls):
        """获取「已完成」状态实例"""
        return cls.objects.get(slug=cls.STATUS_FINISHED_SLUG)

方案B:自定义模型管理器(更符合Django习惯)

from django.db import models

class OrderStatusManager(models.Manager):
    def get_new(self):
        return self.get(slug=OrderStatus.STATUS_NEW_SLUG)
    
    def get_in_progress(self):
        return self.get(slug=OrderStatus.STATUS_IN_PROGRESS_SLUG)
    
    def get_finished(self):
        return self.get(slug=OrderStatus.STATUS_FINISHED_SLUG)

class OrderStatus(models.Model):
    STATUS_NEW_SLUG = "new"
    STATUS_IN_PROGRESS_SLUG = "in_progress"
    STATUS_FINISHED_SLUG = "finished"

    status = models.CharField(max_length=20, verbose_name="状态显示名")
    slug = models.SlugField(max_length=20, unique=True, verbose_name="内部唯一标识")

    objects = OrderStatusManager()

2. 确保数据库中存在默认状态

为避免不同环境(开发/测试/生产)数据库状态缺失,通过信号自动创建默认状态:

在你的app目录下创建signals.py:

from django.db.models.signals import post_migrate
from django.dispatch import receiver
from .models import OrderStatus

@receiver(post_migrate)
def create_default_order_statuses(sender, **kwargs):
    # 仅在当前app迁移时执行
    if sender.name != "你的app名称":
        return
    
    default_statuses = [
        {"slug": OrderStatus.STATUS_NEW_SLUG, "status": "New"},
        {"slug": OrderStatus.STATUS_IN_PROGRESS_SLUG, "status": "In progress"},
        {"slug": OrderStatus.STATUS_FINISHED_SLUG, "status": "Finished"},
    ]
    # 使用get_or_create避免重复创建
    for item in default_statuses:
        OrderStatus.objects.get_or_create(slug=item["slug"], defaults=item)

然后在app的apps.py中注册信号:

from django.apps import AppConfig

class YourAppConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "你的app名称"

    def ready(self):
        import 你的app名称.signals

3. 视图中使用方式

方案A调用示例:

orderx = Order()
orderx.orderStatus = OrderStatus.get_new()
orderx.orderNo = i
orderx.save()

方案B调用示例:

orderx = Order()
orderx.orderStatus = OrderStatus.objects.get_new()
orderx.orderNo = i
orderx.save()

方案优势

  • 彻底摆脱对数据库ID的依赖:ID在不同环境迁移时可能不一致,slug字段是稳定的内部标识
  • 支持多语言/显示文本修改:status字段可以随时修改(比如改成中文“新建”),不影响业务逻辑
  • 代码可读性高:通过明确的方法名获取状态,避免硬编码字符串或数字,降低维护成本

内容的提问来源于stack exchange,提问作者andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 00:52:28