0

I read the django documentation about Database transactions.

Then, this section says:

Django’s default behavior is to run in autocommit mode. Each query is immediately committed to the database, unless a transaction is active.

So, as the section says, Django doesn't use atomic transactions by default?

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
  • Yes, Django doesn't use atomic transactions by default. – solarissmoke Mar 28 '22 at 04:57
  • Also how would having atomic transactions for the database change anything? I assume you mean the user spends time filling the form meanwhile someone else has already updated the model instance. That isn't something database transactions would help with (In fact it would be a very messy feature to implement such locking) – Abdul Aziz Barkat Jul 26 '22 at 06:38

1 Answers1

3

Django doesn't use Atomic Transaction by default for Django views while Django uses Atomic Transaction by default for Django admin.

Using PostgreSQL, I experimented if Atomic Transaction is used for Django views by default or not with the code below. "SELECT", "INSERT", "UPDATE" and "DELETE" queries are run by "Animal" class code in "test()" view on "views.py" as shown below. *You can also see my answer which experimented if Atomic Transaction is used for Django admin by default or not:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

def test(request):

    animal = Animal.objects.all() # For "SELECT" query
    print(animal) # Needed to run "SELECT" query

    Animal(name='Dog').save() # For "INSERT" query

    Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

    Animal.objects.filter(name="Cat").delete() # For "DELETE" 

    return HttpResponse("Test")

And, this is "urls.py" below:

# "store/urls.py"

from django.urls import path
from . import views

app_name = "store"

urlpatterns = [
    path('test/', views.test, name="test"),
]

Then, I open the url "http://localhost:8000/store/test/" to run "test" view as shown below:

enter image description here

Now, between "BEGIN" and "COMMIT" queries, only "DELETE" query is run by "Animal" class code in "test()" view., So, Atomic Transaction is not used for Views by default. *These logs below are the query logs of PostgreSQL. You can check On PostgreSQL, how to log SQL queries with transaction queries such as "BEGIN" and "COMMIT":

enter image description here

Next, for "test()" view, I put "@transaction.atomic" decorator as shown below:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

@transaction.atomic # Here
def test(request):
    
    animal = Animal.objects.all() # For "SELECT" query
    print(animal) # Needed to run "SELECT" query

    Animal(name='Dog').save() # For "INSERT" query

    Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

    Animal.objects.filter(name="Cat").delete() # For "DELETE" 

    return HttpResponse("Test")

Or, for "test()" view, I put "with transaction.atomic():" as shown below:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

def test(request):

    with transaction.atomic(): # Here
    
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" 

        return HttpResponse("Test")

Or, for "test()" view, I put 'ATOMIC_REQUESTS': True to my PostgreSQL settings in "settings.py" as shown below:

# "core/settings.py"

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'postgres',
        'USER':'postgres',
        'PASSWORD':'admin',
        'HOST':'localhost',
        'PORT':'5432',
        'ATOMIC_REQUESTS': True, # Here
    }
}

Then, I open the url "http://localhost:8000/store/test/" to run "test" view as shown below:

enter image description here

Now, between "BEGIN" and "COMMIT" queries, "SELECT", "INSERT", "UPDATE" and "DELETE" queries are run by "Animal" class code in "test()" view. So now, Atomic Transaction works:

enter image description here

Next, for "test()" view, I put both "@transaction.atomic" decorator and "with transaction.atomic():" as shown below:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

@transaction.atomic # Here
def test(request):
    
    with transaction.atomic(): # Here
        
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" 

        return HttpResponse("Test")

And, I also put 'ATOMIC_REQUESTS': True to my PostgreSQL settings in "settings.py" as shown below:

# "core/settings.py"

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'postgres',
        'USER':'postgres',
        'PASSWORD':'admin',
        'HOST':'localhost',
        'PORT':'5432',
        'ATOMIC_REQUESTS': True, # Here
    }
}

Then, I open the url "http://localhost:8000/store/test/" to run "test" view as shown below:

enter image description here

Now, between "BEGIN" and "COMMIT" queries, 2 "SAVEPOINT" and 2 "RELEASE SAVEPOINT" queries are run as shown below:

enter image description here

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129