首页 > 解决方案 > 根据其他列更新 django 模型列

问题描述

我有一个模型

class tbl_payment(models.Model):
    document_id                     = models.ForeignKey(tbl_invoice, on_delete=models.CASCADE)
    client_id                       = models.ForeignKey(tbl_customer, on_delete=models.CASCADE)
    total_amount                    = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    paid_amount                     = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    balance                         = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    date                            = models.DateField(blank=True, null=True)
    status                          = models.CharField(max_length=50)

现在我想做的是每当添加新记录或现有记录更改时,balance都应该更新为total_amountpaid_amount(简单数学)之间的差异,并且根据我的balance列,我想保存statusPaidPartialUnpaid

我想避免balance在我的视图中计算然后保存在数据库中,相反,我想将此部分移交给我的模型,以便我的模型负责处理balance并且我可以避免我下意识地害怕的错误。

我开始知道这是这样做的

class tbl_payment(models.Model):
    document_id                     = models.ForeignKey(tbl_invoice, on_delete=models.CASCADE)
    client_id                       = models.ForeignKey(tbl_customer, on_delete=models.CASCADE)
    total_amount                    = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    paid_amount                     = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    balance                         = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    date                            = models.DateField(blank=True, null=True)
    status                          = models.CharField(max_length=50)

    @property
    def balance(self, value):
        return self.total_amount - paid_amount
        

但是我应该通过什么来代替value?当我试图获得due_amount这样的价值时

tbl_bulk_payment.objects.get(pk=1).due_amount

它给due_amount() missing 1 required positional argument: 'value'

这样做的正确方法是什么?

标签: djangodjango-modelsorm

解决方案


你必须重写 save() 函数

    class tbl_payment(models.Model):
        class Status(models.TextChoices):
            paid = 'Paid', 'Paid'
            partial = 'Partial', 'Partial'
            unpaid = 'Unpaid', 'Unpaid'
            
        document_id                     = models.ForeignKey(tbl_invoice, on_delete=models.CASCADE)
        client_id                       = models.ForeignKey(tbl_customer, on_delete=models.CASCADE)
        total_amount                    = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
        paid_amount                     = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
        balance                         = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
        date                            = models.DateField(blank=True, null=True)
        status                          = models.CharField(max_length=50, choices=Status.choices)
    
        def save(self, *args, **kwargs):
            self.balance = self.total_amount - self.paid_amount
            
            if self.balance >= 0:
                self.status = Status.paid
            elif self.paid_amount == 0:
                self.status = Status.unpaid
            else:
                self.status = Status.partial
    
            super(tbl_payment, self).save(*args, **kwargs)

PS 您的模型类名称不遵循 python 或 Django 命名规则。 class Payment(models.Model)会更好。

document_id=> document。因为

payment = Payment.objects.get(pk=1)
payment.document_id

在这种情况下payment.document_id将返回document实例。(不是文档实例的 ID)。所以document更像 Django 的风格比document_id


推荐阅读