Transaction Atomic With Django

Shivani Kakrecha
2 min readMar 6, 2019

--

Django gives us a few ways to control how database transactions are managed. We mostly used transaction property into the transaction related queries. Each query is directly committed to the database unless a transaction is active cause of Django is run in auto-commit mode.

A transaction is an atomic set of database queries. These functions take a using argument which should be the name of a database. If it isn’t provided, Django uses the “default” database. Django will refuse to commit or to rollback when an atomic() block is active because that would break atomicity.

Django provides a single API to control database transactions. Atomicity is the defining property of database transactions. atomic allows us to create a block of code within which the atomicity on the database is guaranteed.

When auto-commit is turned on and no transaction is active, each SQL query gets wrapped in its own transaction. In other words, not only does each such query start a transaction, but the transaction also gets automatically committed or rolled back, depending on whether the query succeeded.

Django ORM uses transactions or savepoints automatically to guarantee the integrity of ORM operations that require multiple queries, especially delete() and update() queries.

Few things are should be clear in mind while writing the transaction block with atomic().

  1. Never used try catch block into the transaction block. Cause, if the error is raise than the whole block is failed to execute. Into transaction block, we write some code lines than must priority is all lines should be error free. If any case we used try catch block than only raise exception. Do not handle exception into transaction atomic block.
class MyView(View):
"""
This code for only example of above point. do not use this.
"""
@transation.atomic
def post(self, request, *args, **kwargs):
try:
some_object = SomeModel(...)
some_object.save()

if something:
raise exception.NotAcceptable()
# When the workflow comes into this condition, I think the previous save should be undome
# Whant am I missing?

except exception.NotAcceptable, e:
# do something

2) Use select_for_update method to update any queries. Also with a filter or first(). By default, select_for_update() locks all rows that are selected by the query until the transaction is done. For example, rows of related objects specified in select_related() are locked into a transaction.

@classmethod
def deposit(cls, id, amount):
"""
This is for sample code of select_for_update use with transaction atomic(). it is use for manage concurrency.
"""
with transaction.atomic():
account = (
cls.objects
.select_for_update()
.get(id=id)
)

account.balance += amount
account.save()
return account

We can use into different ways like,

  1. As a decorator

from django.db import transaction

@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()

2) As a context manager

from django.db import transaction

def viewfunc(request):
# This code executes in autocommit mode (Django's default).
do_stuff()

with transaction.atomic():
# This code executes inside a transaction.
do_more_stuff()

--

--

Shivani Kakrecha

Python, Django Developer, knowledge of G-suit and Gmail AddOn & API integration into React JS/ Native.