Reputation: 51
I am using a signal to update fields in the profile table when a new investment is made.
Having used a number of print statements inside the update_users_investments function I can see that the function is being called and it is doing the right calculation.
However, it is not saving to the database and there is no error.
Can you see why it's not saving? And is there a better way to debug the save method? I have looked around and can't see anything, and not knowing why it isn't saving is very frustrating.
Elsewhere in my code I use similar signals to save to other tables that appear to work fine.
The signal
@receiver(post_save, sender=Investment)
def update_users_investments(sender, instance, created, **kwargs):
user = Profile.objects.get(user=instance.user.user)
total_investments = user.total_invested
investment = instance.transaction_type * instance.price * instance.number_shares
user.total_invested = total_investments + investment
user.save()
The model to be saving to:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
total_invested = models.DecimalField(max_digits=5, decimal_places=2)
cash_avaliable = models.DecimalField(max_digits=5, decimal_places=2,
null=True)
The investment model (which is where the signal is coming from):
class Investment(models.Model):
"""Model representing each investment made by users"""
user = models.ForeignKey(Profile, on_delete=models.DO_NOTHING)
team_code = models.ForeignKey(Team,
on_delete=models.DO_NOTHING)
transaction_type = models.IntegerField(choices=((-1, "Sell"), (1, "Buy")),
help_text="Show whether transaction\
was a buy or sell",
verbose_name="Transaction Type")
number_shares = models.IntegerField(help_text="Number of shares bought or \
sold in this transaction",
verbose_name="Number of Shares")
price = models.DecimalField(help_text = "Current Price of the team",
verbose_name = "Current Price", decimal_places=2, max_digits=5)
transaction_date = models.DateTimeField(auto_now=True, help_text="Date and \
Time of transaction",
verbose_name="Transaction Date")
transaction_mode = models.IntegerField(choices=((-1, "User Generated"),
(1,
"Automatically Generated")))
Have solved this - as pointed out the user = Profile.objects.get(user=instance.user.user) isn't required.
@receiver(post_save, sender=Investment)
def update_users_investments(sender, instance, created, **kwargs):
total_investments = instance.user.total_invested
investment = instance.transaction_type * instance.price * instance.number_shares
instance.user.total_invested = total_investments + investment
instance.user.save()
Now appears to make it work :-)
Upvotes: 5
Views: 14147
Reputation: 505
I was having the same problem and all my debug prints looked correct but I couldn't get the data set.
According to https://realpython.com/modeling-polymorphism-django-python/:
"You used Django’s built-in validation mechanism to enforce data integrity rules. clean() is only called automatically by Django forms. For objects that are not created by a Django form, you need to make sure to explicitly validate the object."
I tried both directly saving to the field and using a save() in the view and also using a method in the model. For example:
def set_date_paid(self,date_str):
self.date_paid = date_str
With this method I was still doing the save() in the view that called the method. I decided to do the save of the field in the models' method like:
def set_date_paid(self,date_str):
self.date_paid = date_str
self.save(update_fields=["date_paid"])
The result was I finally got an error that my data was not valid.
My mistake was that I expected to get a validation error. But as the article and manual point out, this is not the case.
Once I knew this, I made sure I was screening the data to the proper format and the data saved fine. I have not gone back to doing the save() in the view but I'm sticking with working from the model even for the single field updates. I'm not very "pythonic" yet, so I'm sure there are better ways, but I hope this helps you.
Upvotes: 4