创建一个类的实例等于定义 Django

2024-05-23 20:51:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我有课:

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()])

我能把总价定义的回报保存成美元金额吗?我想在我的生活中这样做管理员.py我将能够调用美元金额到搜索字段和其他一些可能的字段。你知道吗


Tags: selfforverbosemodelmodelsproduct金额amount
1条回答
网友
1楼 · 发布于 2024-05-23 20:51:15

在性能和获得所需的准确行为方面,需要考虑一些因素。您可能会问以下几个问题:

  • 您多久保存一次采购订单,多久检索一次?你知道吗
  • 如果与现有采购订单相关的项目价格发生变化,是否会影响总金额?你知道吗
  • 是否允许用户通过添加/删除项目来编辑其采购订单?你知道吗

如果这是采购订单的完整实现,那么我猜您只需创建并保存一次PurchaseOrder对象,然后多次检索它。我想,当相关产品的价格发生变化时,你不希望总数发生变化,但这只是一个猜测。如果你真的想改变它,你必须实现类似于我建议的逻辑,如果你允许人们编辑他们的订单,但是你必须在Product模型本身上实现它。你知道吗

现在有两种不同的情况:

你不允许人们改变他们的命令

这是一个简单的例子,因为您只需要检索一次dollar_amount,然后保存它。我建议使用一个私有字段来表示实际金额,并使用一个属性来访问private属性,如果还没有设置的话,就设置它。通常您会重写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并保存它,但我认为没有更简单的方法。你知道吗

相关问题 更多 >