Django小型库存管理应用模型优化与功能扩展技术问询
Django小型库存管理应用模型优化与问题解答
我开发了一款用于管理小型库存的Django应用,核心模型逻辑为:每个Account对应一个Inventory,Inventory中的产品由InventoryProduct维护,库存数量通过Transaction及TransactionItem更新。Transaction分为IN/OUT两种类型,分别对应库存增减,TransactionItem记录单条交易的具体产品与数量。现有models.py代码如下:
class Inventory(models.Model): account = models.ForeignKey( "accounts.Account", on_delete=models.DO_NOTHING, null=False, blank=False ) class InventoryProduct(models.Model): inventory = models.ForeignKey("Inventory", on_delete=models.CASCADE) sku = models.ForeignKey( "products.SKU", on_delete=models.DO_NOTHING, null=False, blank=False ) quantity = models.PositiveIntegerField( default=0 ) class Transaction(models.Model): IN = 1 OUT = 0 TYPE_CHOICES = ( (IN, "Incoming"), # 入库 (OUT, "Outgoing"), # 出库 ) inventory = models.ForeignKey("Inventory", on_delete=models.CASCADE) transferred_to = models.ForeignKey( "Inventory", on_delete=models.CASCADE, blank=True, null=True ) code = models.UUIDField(default=uuid.uuid4) transaction_type = models.PositiveSmallIntegerField( choices=TYPE_CHOICES, default=IN ) transaction_date = models.DateTimeField(auto_now_add=True) notes = models.TextField(null=True, blank=True) class TransactionItem(models.Model): transaction = models.ForeignKey("Transaction", on_delete=models.CASCADE) item = models.ForeignKey("InventoryProduct", on_delete=models.CASCADE) quantity = models.IntegerField() def save(self, *args, **kwargs): super().save(*args, **kwargs) self.item.quantity += self.quantity self.item.save()
模型优化建议
- Inventory模型:
- 新增
name字段(如name = models.CharField(max_length=100)),方便区分同一账户下的不同库存(适配未来多仓库扩展场景)。 - 将
on_delete=models.DO_NOTHING改为models.PROTECT或models.CASCADE,避免Account删除后遗留孤立的Inventory记录,引发外键数据不一致问题。
- 新增
- InventoryProduct模型:
- 添加唯一约束,确保同一库存下同一SKU仅存在一条记录:
class Meta: constraints = [ models.UniqueConstraint(fields=['inventory', 'sku'], name='unique_inventory_sku') ] - 新增库存校验逻辑,避免TransactionItem更新时导致库存变为负数(比如在TransactionItem保存前检查
self.item.quantity + self.quantity >= 0)。
- 添加唯一约束,确保同一库存下同一SKU仅存在一条记录:
- Transaction模型:
- 改用Django的
TextChoices替代数字枚举,提升代码可读性:from django.db import models class TransactionType(models.TextChoices): IN = 'IN', '入库' OUT = 'OUT', '出库' # 修改transaction_type字段: transaction_type = models.CharField( max_length=3, choices=TransactionType.choices, default=TransactionType.IN ) - 可明确
inventory为交易的关联库存,transferred_to仅用于转移场景的目标库存,清晰区分普通出库与库存转移。
- 改用Django的
- TransactionItem模型:
- 移除模型内的
save重写逻辑,改用post_save信号或业务逻辑层处理库存更新——批量创建TransactionItem时(bulk_create)不会触发模型save方法,会导致库存不更新。示例信号实现:from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=TransactionItem) def update_inventory_quantity(sender, instance, created, **kwargs): if created: instance.item.quantity += instance.quantity instance.item.save() - 新增字段校验,比如当交易类型为OUT时,确保
quantity为负数,且对应InventoryProduct的库存足够扣减。
- 移除模型内的
技术问题解答
1. 库存间产品转移功能实现与溯源
无需拆分独立的OUT和IN交易,可通过现有模型扩展实现完整转移链路:
- 转移逻辑:创建一条OUT类型的Transaction,
inventory设为来源库存,transferred_to设为目标库存;对应的TransactionItem的quantity设为负数(比如转移5件则填-5)。同时创建一条IN类型的Transaction,inventory设为目标库存,新增related_transaction外键指向之前的OUT交易,用于关联转移记录:# 在Transaction模型中添加 related_transaction = models.ForeignKey( 'self', on_delete=models.SET_NULL, null=True, blank=True, related_name='linked_transactions' ) - 原子性保障:用数据库事务包裹整个转移操作,避免只创建了OUT交易却未创建IN交易的情况:
from django.db import transaction def transfer_inventory(source_inventory, target_inventory, sku, quantity): with transaction.atomic(): # 获取来源库存的InventoryProduct source_item = InventoryProduct.objects.get(inventory=source_inventory, sku=sku) # 创建OUT交易 out_transaction = Transaction.objects.create( inventory=source_inventory, transferred_to=target_inventory, transaction_type=TransactionType.OUT ) TransactionItem.objects.create( transaction=out_transaction, item=source_item, quantity=-quantity ) # 创建IN交易并关联OUT交易 target_item, _ = InventoryProduct.objects.get_or_create(inventory=target_inventory, sku=sku) in_transaction = Transaction.objects.create( inventory=target_inventory, related_transaction=out_transaction, transaction_type=TransactionType.IN ) TransactionItem.objects.create( transaction=in_transaction, item=target_item, quantity=quantity ) - 溯源实现:通过Transaction的
related_transaction字段,可直接关联到对应的反向交易,从而追踪产品从哪个库存转出、转入哪个库存,完整还原转移链路。
2. 整合Order到现有模型体系
新增Order相关模型,并与Transaction关联,实现订单入库与库存转移的区分:
- 新增Order与OrderItem模型:
class Order(models.Model): order_number = models.CharField(max_length=50, unique=True) customer = models.ForeignKey('accounts.Account', on_delete=models.CASCADE) order_date = models.DateTimeField(auto_now_add=True) STATUS_CHOICES = ( ('PENDING', '待处理'), ('COMPLETED', '已完成'), ('CANCELLED', '已取消'), ) status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='PENDING') class OrderItem(models.Model): order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items') sku = models.ForeignKey('products.SKU', on_delete=models.CASCADE) quantity = models.PositiveIntegerField() price = models.DecimalField(max_digits=10, decimal_places=2) - 关联Transaction与Order:在Transaction模型中添加外键:
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True, blank=True, related_name='transactions') - 业务逻辑整合:
- 当订单完成入库时,创建IN类型的Transaction,关联对应的Order;TransactionItem可关联对应的OrderItem,实现订单产品到库存交易的追踪。
- 库存转移的Transaction则不关联Order,以此区分库存的来源是订单还是内部转移。
内容的提问来源于stack exchange,提问作者Dail
相关产品推荐
相关产品推荐

