我上课了:
class PurchaseOrder(models.Model):
product = models.ManyToManyField('Product')
dollar_amount = models.FloatField(verbose_name='Total Price')
def total_price(self):
return sum([p.price_for_each_item for p in self.product.all()])
我可以这样做,以便将total_price定义的回报保存到美元金额中吗?我想这样做,所以在我的admin.py中,我可以将dollar_amount调用到search_field和其他一些字段。
答案 0 :(得分:1)
有一些与性能相关的考虑事项并获得您想要的确切行为。您可能会问的几个问题是:
如果这是您对采购订单的完整实施,那么我猜您只需创建并保存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
并保存,但我认为没有更简单的方法。