I'm afraid there is no "one size fits all" solution to the problem you described.
It seems to me that you have a good understanding of what should be done, so let me suggest one other possible solution.
Assuming that you have a large number of users and each user has a small or moderate amount of transactions (so that processing a single user's transactions doesn't take ages), you could do something like this in your South data migration (using the old Django transactions as you asked the question before Django 1.6 was out):
from django.db import transaction
for user in orm.User.objects.all():
with transaction.commit_on_success():
user._total = calculate_sum_of_transactions_for_user(user)
user.transactions_migrated = True
user.save()
Then you could add the following method to your User model:
@property
def total(self):
if self.transactions_migrated:
return self._total
else:
return calculate_sum_of_transactions_for_user(user)
And the transaction creation code could look like this:
class Transaction(models.Model):
amount = models.DecimalField(...)
def save(self, ...):
super().save(...)
if self.user.transactions_migrated:
self.user._total = F('_total') + self.amount
self.user.save()
You could even get rid of the transactions_migrated
field and replace it with some _total is None
check.