python - select_for_update kind of functionality in django 1.3 to avoid race condition -


i have accounts model in django project, stores account balance(available money) of users. every deduction account of users preceded amount check i.e. check if user has x amount of money or more. if yes go ahead , deduct amount.

account = accountdetails.objects.get(user=userid) if int(account.amount) >= fare:     account.amount = account.amount-fare     account.save() 

now want put lock in first .get() statement, race conditions can avoided. user makes request twice, , application executes above code twice simultaneously, causing 1 of requests override other.

i found out select_for_update() want. locks row until end of transaction.

account = accountdetails.objects.select_for_update().get(user=userid) 

but it's available in django 1.4 or higher , i'm still using django 1.3 , moving new version can't done right now. ideas how can achieve in present django version?

looks you'll have use raw sql. had through current code , think more hassle try , backport write sql.

account = accountdetails.objects.raw(     "select * yourapp_accountdetails update user = %s", [user.id] ) 

for convenience , keep code dry can add method accountdetails model or something.

class accountdetails(models.model):      @classmethod     def get_locked_for_update(cls, user):         return cls.objects.raw(             "select * yourapp_accountdetails update user = %s", [user.id]         ) 

yourapp name of application have given when ran startapp. i'm assuming have foreign key relationship on accountdetails user model of kind.

the current implementation of select_for_update on django 1.5 looks this:

def select_for_update(self, **kwargs):     """     returns new queryset instance select objects     update lock.     """     # default false nowait     nowait = kwargs.pop('nowait', false)     obj = self._clone()     obj.query.select_for_update = true     obj.query.select_for_update_nowait = nowait     return obj 

so that's pretty simple code. setting few flags on query object. flags won't mean when query executed. @ point you'll need write raw sql. @ point need query on accountdetails model. put there now. maybe later you'll need on model. that's when you'll have decide how share code between models.


Comments