Решение первое:
Я думаю, что вместо изменения в 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)
Решение второе:
Но, если честно, Solution One не кажется мне хорошим.Причина в том, что вы сохраняете одни и те же данные в 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
(так как он динамически вычисляет сумму_доплаты по БД) из предыдущего решения, то вы можетевсегда annotate
значение.Например:
Для этого решения вам нужно изменить модель Expense
и добавить related_name
:
class Expense(models.Model):
pay_from = models.CharField(max_length=200)
payment_option = models.ForeignKey('Ledger', on_delete=models.CASCADE, <b>related_name='expenses'</b>)
Затем используйте этот related_name
в таком запросе (к вашему сведению: вы не можете сохранить метод def amount_to_pay(...)
в Ledger модели для следующего примера использования):
from django.db.models import Sum, F, ExpressionWrapper, IntegerField
ledgers = Ledger.objects.all().annotate(expense_sum=Sum(<b>'expenses__amount_to_pay'</b>)).annotate(<b>amount_to_pay=ExpressionWrapper(F('opening_balance') - F('expense_sum'), output_field=IntegerField())</b>)
# usage one
for l in ledgers:
l.amount_to_pay
# usage two
ledgers.values('amount_to_pay')