Reputation: 74
I want to update a related model every time a foreign key is changed using signals, similar to m2m_changed
but for a foreign key.
User model:
class User(AbstractUser):
balance = models.FloatField(default=0)
Transaction model:
class Transaction(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='transactions')
order = models.OneToOneField('Payment.Order', on_delete=models.CASCADE, related_name='transaction')
transaction_type = models.CharField(choices=[
('transfer', 'Transfer'),
('received', 'Received'),
], max_length=20, default='transfer')
created = models.DateTimeField(auto_now_add=True)
I need that when a new transaction is created under the User, it's collected to the balance.
Signal code:
@receiver(pre_save, sender=User)
def collect_transaction(sender, instance, **kwargs):
balance = instance.transactions.aggregate(Sum('order__price'))
print(balance)
but it works only when I update it from the User model, and not Transaction.
For example, this code will make the signals work:
user.transactions.add(transaction)
user.save()
Whereas this code won't make the signals work:
Transaction.objects.create(user=1, order=1, transaction_type='received')
Upvotes: 3
Views: 1451
Reputation: 8207
Your signal will only be sent when the User
model is saved. It seems you want it to be sent when any Transaction
is saved, so you should try using Transaction
as the sender instead of User:
@receiver(post_save, sender=Transaction)
def collect_transactions(sender, instance, **kwargs):
user = instance.user
user.balance = user.transactions.aggregate(Sum('order__price'))
user.save()
As for your original example of having a signal when User is saved, I'm trying to think of a case where you'd be updating User but not updating its related transactions and yet need the balance to be updated. If there does exist such a case, you might just be better off overriding the save()
method on the User model.
Upvotes: 1