0

I have Django 1.11 app with PostgreSQL. Take a look at code below.

Is it possible to have race condition there? I am afraid I could get race condition on diff=-account.hours. Does transaction.atomic save from race condition?

from django.db import transaction def write_off(account_ids): accounts = Account.objects.filter(id__in=account_ids) for account in accounts: with transaction.atomic(): MyLog.objects.create( hours=0, operation_type=LOG_OPERATION_WRITE_OFF, diff=-account.hours, ) Account.objects.filter(pk=account.pk).update(hours=0) 
4
  • 2
    From what it appears to me, your code should not work. account will be a QuerySet and not a single Account instance. Therefor it will not have .hours and .pk. Commented Jan 22, 2018 at 14:40
  • @KlausD. I have edited the question, thank you. Commented Jan 22, 2018 at 14:45
  • And now explain where you see a possible race condition. Where is the race? Commented Jan 22, 2018 at 14:48
  • @KlausD. in the line diff=-account.hours. I take account instance, then save account.hours to MyLog, and then set account.hours=0. Could the value of account.hours be changed after I create MyLog with outdated value? Commented Jan 22, 2018 at 14:54

1 Answer 1

5

The transaction.atomic() means that all your objects are created/saved in a single transaction, or none of them are. It does not prevent the accounts being modified by another request.

You could look at select_for_update:

def write_off(account_ids): with transaction.atomic(): accounts = Account.objects.select_for_update().filter(id__in=account_ids) for account in accounts: MyLog.objects.create( hours=0, operation_type=LOG_OPERATION_WRITE_OFF, diff=-account.hours, ) accounts.update(hours=0) # use fewer queries by updating all accounts at once 
Sign up to request clarification or add additional context in comments.

2 Comments

Updating all accounts at once is not a good idea, because if one update fails, all updates would be rolled back.
You can rearrange the code to suit your needs. Note that select_for_update must be inside an atomic block.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.