Django - 基于另一个字段更新模型字段

Posted

技术标签:

【中文标题】Django - 基于另一个字段更新模型字段【英文标题】:Django - Update model field based on another field 【发布时间】:2014-12-25 07:13:26 【问题描述】:

我是 Django 和 Python 的新手,我想做一些我以前在 Java EE 中经常做的事情。

考虑以下模型(仅相关类):

class Item(models.Model):
    name = models.CharField(max_length=40)
    default_price = models.DecimalField(max_digits=6, decimal_places=2, default=50)

    def __unicode__(self):
        return self.name


class SaleDetail(models.Model):
    item = models.ForeignKey(Item)
    deposit = models.ForeignKey(Deposit)
    quantity = models.PositiveIntegerField()
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)
    sale = models.ForeignKey(Sale)

    def item_updated(self, value):
        if self.unit_price == None:
            self.unit_price = value

我想要做的是每次将Item 添加到SaleDetail 时,如果SaleDetail 是新的或未设置unit_price,则将SaleDetail.unit_price 更新为Item.default_price

我过去在 Java POJO 中所做的是将这个逻辑包含在 setter 方法中。我尝试使用 python 属性来封装 item 属性,但是 Django 直接在后台更新了该字段,因此这会破坏一些自动功能。

我也尝试子类化 ForeignKey 以接受回调函数,但我找不到在容器类上调用方法的方法。

我想这样做,以便为 UI 提供默认值,但我不想在视图逻辑中包含此逻辑,因为从概念上讲,我认为此逻辑应该在模型上(服务器端)

这种情况下的其他用途是更新每个销售细节和销售的总计。我想在用户决定保存销售之前计算这个,所以保存信号不起作用。

谢谢!

【问题讨论】:

【参考方案1】:

看看这是否适合你。我们重写 save 方法并检查是否有pk。如果pk 为None,我们知道SaleDetail 是新的。然后,我们看看是否有unit_price。如果没有unit_price,我们将其设置为Item.default_price

class Item(models.Model):
    name = models.CharField(max_length=40)
    default_price = models.DecimalField(max_digits=6, decimal_places=2, default=50)

    def __unicode__(self):
        return self.name


class SaleDetail(models.Model):
    item = models.ForeignKey(Item)
    deposit = models.ForeignKey(Deposit)
    quantity = models.PositiveIntegerField()
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)
    sale = models.ForeignKey(Sale)

    def save(self, *args, **kwargs):
        # Make sure this is the first save (pk should be None) and there is no unit_price set
        if self.pk is None and not self.unit_price:
            self.unit_price = self.item.default_price
        elif not self.unit_price:
            self.unit_price = self.item.default_price

        # Call the original save method
        super(SaleDetail, self).save(*args, **kwargs)

【讨论】:

嗨@Michael,感谢您的回答。但是,正如我在问题中所述,我需要在用户尝试保存对象之前执行此操作。 我个人唯一能想到的另一件事是在模型上添加一个方法来获取unit_price。它将使用与覆盖的保存方法相同的逻辑,除了它会在需要的情况下返回item.default_price。我不完全确定您是如何收集这些信息的(表格?),因此很难在您的情况下提供帮助。如果“SaleDetail”实际上是收据的“行项目”,则将方法放在 SaleDetail 模型上应该可以工作。 很好地使用了覆盖save方法【参考方案2】:

“单价”实际上是两个不同字段的函数。因此,我倾向于这样写:

class Item(models.Model):
    name = models.CharField(max_length=40)
    default_price = models.DecimalField(max_digits=6, decimal_places=2, default=50)

    def __unicode__(self):
        return self.name

class SaleDetail(models.Model):
    item = models.ForeignKey(Item)
    deposit = models.ForeignKey(Deposit)
    quantity = models.PositiveIntegerField()
    entered_unit_price = models.DecimalField(max_digits=6, decimal_places=2, default=None)
    sale = models.ForeignKey(Sale)

    @property
    def unit_price(self, value):
        if self.entered_unit_price is None:
            return self.item.default_price
        else:
            return self.entered_unit_price

    @unit_price.setter
    def unit_price(self, value):
        self.entered_unit_price = value

然后像这样使用它:

print(sd.unit_price)
sd.unit_price = 500 
sd.save()

【讨论】:

现在我有了更多的经验,我可以看到我尝试做的事情在 django 生态系统中没有意义,但是由于这正确回答了我的问题,我接受了答案。谢谢! @AníbalRivero 为什么没有意义? @PiotrChojnacki,我想做的是使用 django admin 作为最终用户的生成 UI,这不是一个好主意,因为它不是为此而生的。

以上是关于Django - 基于另一个字段更新模型字段的主要内容,如果未能解决你的问题,请参考以下文章

如何根据具有外键关系的另一个模型更新 Django 模型的字段

当更新同一模型中的另一个特定字段时,如何更新 Django models.DateTimeField?

确保字段对于 Django 模型中的另一个字段是唯一的

Django 模型字段依赖于另一个模型字段

根据另一个字段的值验证 Django 模型字段?

Django:如何创建一个包含另一个模型的所有字段(但与它无关)的新模型?