Django中如何为Product模型关联不同数量Supply物料实现手工项目成本核算
模型设计方案
核心实现思路
你需要的是带额外属性的多对多关系,Django提供了through参数用于定义多对多的中间关联模型,正好可以存储你需要的「物料用量、计量单位」这类额外信息,完全不需要硬编码多个外键字段。
代码实现
第一步:新增中间关联模型+计量单位枚举
from django.db import models from django.utils.translation import gettext_lazy as _ # 计量单位枚举,若后续需要扩展可单独拆为模型 class UnitChoices(models.TextChoices): CUBIC_INCH = 'cubic_inch', _('立方英寸') SQUARE_INCH = 'square_inch', _('平方英寸') EACH = 'each', _('个/件') # 产品-物料中间关联表,存储单种物料的用量信息 class ProductSupply(models.Model): product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='supply_uses') supply = models.ForeignKey(Supply, on_delete=models.CASCADE) usage_amount = models.FloatField(verbose_name='用量') usage_unit = models.CharField(max_length=20, choices=UnitChoices.choices, verbose_name='计量单位') # 自动计算当前物料的成本 @property def item_cost(self): try: if self.usage_unit == UnitChoices.CUBIC_INCH: return round(self.usage_amount * self.supply.cost_per_cubic_inch, 2) elif self.usage_unit == UnitChoices.SQUARE_INCH: return round(self.usage_amount * self.supply.cost_per_square_inch, 2) elif self.usage_unit == UnitChoices.EACH: return round(self.usage_amount * self.supply.cost_per_each, 2) except: return "N/A" def __str__(self): return f"{self.product.name} - {self.supply.name}: {self.usage_amount}{self.get_usage_unit_display()}"
第二步:修改原有Product模型
class Product(models.Model): name = models.CharField(max_length = 200, null = True, blank = True) product_type = models.ForeignKey(ProductType, null = True, blank = True, on_delete = models.CASCADE) # 新增多对多关联,通过中间表ProductSupply实现动态绑定任意数量物料 supplies = models.ManyToManyField(Supply, through=ProductSupply, blank=True) # 自动计算该产品所有物料的总成本 @property def total_material_cost(self): total = 0 for supply_use in self.supply_uses.all(): cost = supply_use.item_cost if cost != "N/A": total += cost return round(total, 2) if total else "N/A" def __str__(self): return self.name
使用说明
- 一个Product可以绑定任意数量的Supply,不需要提前预留字段
- 录入物料时只需选择对应Supply、填写用量、选择计量单位,系统会自动计算单种物料成本、产品总物料成本
- 如果在Django Admin中使用,可以配置Inline实现在Product编辑页直接增删改关联物料:
from django.contrib import admin from .models import Product, ProductSupply class ProductSupplyInline(admin.TabularInline): model = ProductSupply extra = 1 # 默认显示1条空记录,可手动添加更多 @admin.register(Product) class ProductAdmin(admin.ModelAdmin): inlines = [ProductSupplyInline]
内容的提问来源于stack exchange,提问作者Tony Dean
相关产品推荐
相关产品推荐

