python - 如何覆盖 django save 方法以动态更新某些字段?

标签 python django orm

这里我有两个模型。在这些模型中,我想获得 amount_to_pay 的值动态在 Ledger模型。例如,我有这两种模型的两种不同表格,如果用户选择 payment_option,则可以节省费用表格。来自 ledger模型并为 amount_to_pay 提供了一些值(value)字段然后如果只有 ledger.idexpense.payment_option_idamount_to_pay 的值相同分类帐模型中的值应该替换为该值。我该怎么做?

模型.py

     class Expense(models.Model):
        pay_from = models.CharField(max_length=200)
        payment_option = models.ForeignKey('Ledger', on_delete=models.CASCADE)
        amount_to_pay = models.IntegerField(default=0)
        expense_date = models.DateField(default=datetime.date.today)
        expense_type = models.ForeignKey(ExpenseType, on_delete=models.CASCADE)
        note = models.TextField()
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
        slug = AutoSlugField(unique_with='id', populate_from='expense_type')

        def get_amount_to_pay(self):
            return self.amount_to_pay


    class Ledger(models.Model):
        name = models.CharField(max_length=200)
        account_number = models.CharField(max_length=250, unique=True)
        account_type = models.CharField(max_length=200)
        opening_balance = models.IntegerField(default=0)
        amount_to_pay = models.IntegerField(default=0, blank=True, null=True)
        current_balance = models.IntegerField(default=0, blank=True, null=True)
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
        slug = AutoSlugField(unique_with='id', populate_from='name')

        def save(self, *args, **kwargs):
             self.amount_to_pay = Expense.get_amount_to_pay(self)

# here how can i save the amount_to_pay from expense form if the ledger.id and expense.payment_option.id matches??
#i got stuck here.           
 self.current_balance = self.opening_balance - self.amount_to_pay

            super(Ledger, self).save(*args, **kwargs)

最佳答案

解决方案一:

我认为而不是在 Ledger 中更改型号,您应该在 Expense 中更改模型,像这样:

class Expense(models.Model):
    ...
    def save(self, *args, **kwargs):
       self.payment_option.amount_to_pay = self.payment_option.amount_to_pay + self.amount_to_pay
       self.payment_option.save()
       super(Expense, self).save(*args, **kwargs)

解决方案二:

但说实话,方案一 对我来说似乎不太好。原因是您将相同的数据保存在 2 个地方(在费用和分类帐中)。相反,它应该是一次,然后是 amount_to_pay值在 Ledger应该是动态计算的。像这样:
from django.db.models import Sum

class Ledger(...):

     @property
     def amount_to_pay(self):
         # I am using a property method to show the amount_to_pay value.
         # FYI: in this way, you need to remove amount_to_pay field from Ledger model
         return self.opening_balance - self.expense_set.all().aggregate(a_sum=Sum('amount_to_pay')).get('a_sum', 0)

这样,对于每个分类帐,值 amount_to_pay将在运行时动态计算。例如:
 for l in Ledger.objects.all():
     l.amount_to_pay

解决方案三:

如果您对每个 l.amount_to_pay 的 DB 命中都持谨慎态度(因为它从数据库动态计算 amount_to_pay)从以前的解决方案,那么你总是可以 annotate 值(value)。像这样:

对于此解决方案,您需要更改您的 Expense模型并添加 related_name :
class Expense(models.Model):
    pay_from = models.CharField(max_length=200)
    payment_option = models.ForeignKey('Ledger', on_delete=models.CASCADE, related_name='expenses')

然后使用该 related_name在这样的查询中(仅供引用:您不能在 Ledger 模型中保留 def amount_to_pay(...) 方法用于以下用法示例):
from django.db.models import Sum, F, ExpressionWrapper, IntegerField

ledgers = Ledger.objects.all().annotate(expense_sum=Sum('expenses__amount_to_pay')).annotate(amount_to_pay=ExpressionWrapper(F('opening_balance') - F('expense_sum'), output_field=IntegerField()))

# usage one
for l in ledgers:
   l.amount_to_pay

# usage two
ledgers.values('amount_to_pay')

关于python - 如何覆盖 django save 方法以动态更新某些字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56338360/

相关文章:

django - 如何在 heroku 服务器中配置 django-celery

django - Django 站点运行的默认 Web 服务器是什么?如何使我的 Django 站点启用 https?

django - Django 模型上的 Celery 任务

python - 如何使用python访问父目录中的文件?

python - 使用 gitpython 从 git 删除文件

Python 根据第一个属性在内部按日期排序

sql - 预加载与连接获取相同吗?

python - Regex Python - 如何获取不连续出现的次数?

java - 在 hibernate 中映射集合

python - 外键有问题