有一些与性能和获得您想要的确切行为相关的考虑因素。您可能会问的几个问题是:
- 您多久保存一次采购订单以及多久检索一次?
- 如果与现有采购订单相关的商品价格发生变化,是否会影响总金额?
- 人们是否可以通过添加/删除项目来编辑他们的采购订单?
如果这是您对采购订单的完整实现,那么我猜您将PurchaseOrder
只创建并保存一次对象,然后多次检索它。我认为当相关产品的价格发生变化时,您不希望总数发生变化,但这只是一个猜测。如果您确实希望它更改,则必须实现类似于我将建议您允许人们编辑他们的订单时执行的逻辑,但您必须在Product
模型本身上实现它。
现在有两种不同的情况:
你不允许人们改变他们的订单。
这是一个简单的案例,因为您只需要检索dollar_amount
一次然后保存它。我建议对实际金额使用私有字段,并使用属性来访问私有属性并在尚未设置的情况下进行设置。通常您会覆盖save
添加数据的方法,但在这种情况下,您依赖于存在多对多关系,因此必须至少保存一次模型才能获得总价:
from decimal import Decimal
class PurchaseOrder(models.Model):
# Always use a `DecimalField` when you're dealing with currency!!! `FloatField` and the underlying `float` datatype has it's rounding issues, and currency calculations have to be exact.
_dollar_amount = models.DecimalField(verbose_name='Total price')
@property
def dollar_amount(self):
if self._dollar_amount is None:
if self.pk is None:
# Has never been saved, so we can't do anything to calculate the price here.
return Decimal(0.0)
self._dollar_amount = sum(p.price_for_each_item for p in self.product.all())
self.save(update_fields=['_dollar_amount']) # Or self.save() in Django < v1.5
return self._dollar_amount
您允许人们通过添加/删除项目来更改他们的订单。
这可能会变得更复杂一些。dollar_amount
每当创建采购订单和产品之间的新关系或删除一个新关系时,您都需要更新。您可能还想在添加产品时保存产品的价格,否则如果在产品从订单中删除之前价格发生变化,您可能会扣除错误的金额。由于似乎没有办法只覆盖相关管理器上的add()
和delete()
方法等,因此您必须指定一个自定义through
模型:
from django.db.models import F
class PurchaseOrder(models.Model):
product = models.ManyToManyField('Product', through='OrderItem')
dollar_amount = models.DecimalField(verbose_name='Total Price')
class OrderItem(models.Model):
current_price = models.DecimalField()
product = models.ForeignKey(Product)
order = models.ForeignKey(PurchaseOrder)
def save(self, *args, **kwargs):
if self.pk is None:
# new item
self.current_price = self.product.price_for_each_item
self.order.dollar_amount = F('dollar_amount') + self.current_price
self.order.save(update_fields=['dollar_amount']) # Or self.save() in Django < v1.5
super(OrderItem, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
self.order.dollar_amount = F('dollar_amount') - self.current_price
self.order.save(update_fields=['dollar_amount']) # Or self.save() in Django < v1.5
super(OrderItem, self).save(*args, **kwargs)
这将使从采购订单中添加或删除项目变得复杂,因为正常self.product.add()
和self.product.delete()
方法不可用。您必须手动创建OrderItem
并保存它,但我认为没有更简单的方法。