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:

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":

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:

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:

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:

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