Reputation: 269
I have a model like
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)
Now what I want to do is whenever a new record is added, or an existing record changes, balance
should be updated as the difference between total_amount
and paid_amount
(simple maths), and based on my balance
column, I want to save status
as Paid, Partial or Unpaid.
I want to refrain from calculating the balance
in my views and then saving in the database, instead, I want to handover this part to my models so that my models take care of the balance
and I may avoid errors which I am subconsciously afraid of.
I came to know that this is done something like this
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
but what should I pass in place of value
??
also when I try to get due_amount
value like this
tbl_bulk_payment.objects.get(pk=1).due_amount
it gives due_amount() missing 1 required positional argument: 'value'
what is the correct way of doing this??
Upvotes: 1
Views: 2240
Reputation: 681
you have to override clean()
function.
https://docs.djangoproject.com/en/4.2/ref/models/instances/#django.db.models.Model.clean
Model.clean()
... to modify attributes on your model ...
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 clean(self):
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
P.S. your Model class name is not following the python or Django naming rule.
class Payment(models.Model)
would be better.
and document_id
=> document
. because
payment = Payment.objects.get(pk=1)
payment.document_id
in this case payment.document_id
would return document
instance. (not document instance's id). so document
is more Django like style than document_id
Upvotes: 3