0

I have 2 models: Transaction and Wallet, a wallet has multiple transactions. I need to update the amount field in Wallet model whenever a new transaction is created. The way I see is overwrite save method in the model. Currently, I wrote like this

def save(self, *args, **kwargs): 
    if self.kind == "Income":
        self.wallet.amount += self.amount
    elif self.kind == "Outcome":
        self.wallet.amount -= self.amount
    self.wallet.save()
    super(Transaction, self).save(*args, **kwargs)

It creates a new transaction correctly but not update the wallet model. How I can fix that?

3
  • 1
    What class is this method located in? Commented Aug 10, 2020 at 14:20
  • 1
    this method save is inside the Transaction Model or Wallet model ? Commented Aug 10, 2020 at 14:20
  • this save method is inside Transaction model Commented Aug 10, 2020 at 14:22

3 Answers 3

1

You should not be doing this because that information can be accessed via aggregate functions. Check out on django documentation.

But, if for some specific reason you you need to do it, you need to do it after the transaction is saved, with F expression:

from django.db.models import F

def save(self, *args, **kwargs): 
    super(Transaction, self).save(*args, **kwargs)
    if self.kind == "Income":
        self.wallet.amount = F('amount') + self.amount
    elif self.kind == "Outcome":
        self.wallet.amount = F('amount') - self.amount
    self.wallet.save()
Sign up to request clarification or add additional context in comments.

3 Comments

I just try it but the amount of wallet still the same as before
I just noticed, you need to use F object for such cases, I updated my answer.
It because my condition didn't trigger. It should be self.kind.name === "Income". Thank you so much.
0

Did you check to see that your conditional statements are getting triggered?

This should actually work without you having to call self.wallet.save() if you have already passed a valid Wallet object to the Transaction.

def save(self, *args, **kwargs): 
    if self.kind == "Income":
        self.wallet.amount += self.amount
    elif self.kind == "Outcome":
        self.wallet.amount -= self.amount
    super(Transaction, self).save(*args, **kwargs)

See: https://docs.djangoproject.com/en/3.1/topics/db/queries/#saving-changes-to-objects

For information on how to save Object references.

So I think two things could be going wrong. Either your conditional statements are not getting triggered, or you are not passing a valid Wallet Object reference to the Transaction.

Either way...I think this is a good use case for Django's signals. First, I would remove the save method you have, and in the Transaction model I would add

def update_transaction_wallet(sender, instance, **kwargs):
    if instance.kind == "Income":
        instance.wallet.amount += instance.amount
    elif instance.kind == "Outcome":
        instance.wallet.amount -= instance.amount

signals.post_save.connect(update_transaction_wallet, sender=Transaction)

You may have to tweak this a bit in order for it to work in your specific case. You didn't provide a lot of information about your models and situation.

But basically, this bit of code tells Django that whenever a Transaction Objects gets saved to also run the update_transaction_wallet() method. See: https://docs.djangoproject.com/en/3.0/topics/signals/

2 Comments

Yeah, like you said my condition hasn't got trigger. You are my lifesaver. Thank you so much
I got another problem. Do you know how to not create a new transaction if the amount of transaction greater than the amount of wallet and return an error message for the user?
0

You have to instantiate Wallet and then make the proper addition or subtraction on it.

I would do it inside a Transaction method, which you will call on save or any other place. and if saves fail, rowback the wallet amount too ;)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.