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
相关产品推荐
相关产品推荐

