使类的实例等于Django的定义

时间:2013-08-08 17:29:43

标签: python django class

我上课了:

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和其他一些字段。

1 个答案:

答案 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并保存,但我认为没有更简单的方法。