Django admin: Turning off DB transactions
Question:
I noticed that by default, all updates in the django admin site are done as transactions.
I need to either:
– turn off transactions (globally or for a particular admin view)
– inside of a save() method of an entity being saved via the admin interface, commit the transaction
The reason is that I overrode the save() method, and am notifying an external, non-django system about the change that just took place. However, the external system does not see the update since django has still not committed the transaction.
Does anyone have any suggestions on how to accomplish this?
Answers:
You can use commit_manually to get full control of a transaction in a particular view/function.
A better solution might be to investigate your database’s transaction-isolation setting, since that’s the real reason why the external process can’t “see” the update…
Only for when changing(updating) data on Django Admin, you can turn off transaction by overriding changeform_view(). *You can also see my post explaining about how to turn off all transactions in Django Admin.
For example, there is Person()
model below:
# "store/models.py"
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
Then, you need to override changeform_view()
as shown below. *object_id
is None
when adding data while object_id
is not None
when changing data:
# "store/admin.py"
from django.contrib import admin
from .models import Person
from django.db import transaction
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
csrf_protect_m = method_decorator(csrf_protect)
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@csrf_protect_m
def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
if object_id is None:
with transaction.atomic(using=router.db_for_write(self.model)):
return self._changeform_view(request, object_id, form_url, extra_context)
else:
return self._changeform_view(request, object_id, form_url, extra_context)
Now, when adding data:
Transaction is used as shown below. *I use PostgreSQL and these logs below are the queries of PostgreSQL and you can check how to log PostgreSQL queries with transaction:
But, when changing data:
Transaction is not used as shown below:
If you don’t override changeform_view()
as shown below:
# "store/admin.py"
from django.contrib import admin
from .models import Person
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
pass
Then, change data:
Transaction is used as shown below:
I noticed that by default, all updates in the django admin site are done as transactions.
I need to either:
– turn off transactions (globally or for a particular admin view)
– inside of a save() method of an entity being saved via the admin interface, commit the transaction
The reason is that I overrode the save() method, and am notifying an external, non-django system about the change that just took place. However, the external system does not see the update since django has still not committed the transaction.
Does anyone have any suggestions on how to accomplish this?
You can use commit_manually to get full control of a transaction in a particular view/function.
A better solution might be to investigate your database’s transaction-isolation setting, since that’s the real reason why the external process can’t “see” the update…
Only for when changing(updating) data on Django Admin, you can turn off transaction by overriding changeform_view(). *You can also see my post explaining about how to turn off all transactions in Django Admin.
For example, there is Person()
model below:
# "store/models.py"
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
Then, you need to override changeform_view()
as shown below. *object_id
is None
when adding data while object_id
is not None
when changing data:
# "store/admin.py"
from django.contrib import admin
from .models import Person
from django.db import transaction
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
csrf_protect_m = method_decorator(csrf_protect)
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@csrf_protect_m
def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
if object_id is None:
with transaction.atomic(using=router.db_for_write(self.model)):
return self._changeform_view(request, object_id, form_url, extra_context)
else:
return self._changeform_view(request, object_id, form_url, extra_context)
Now, when adding data:
Transaction is used as shown below. *I use PostgreSQL and these logs below are the queries of PostgreSQL and you can check how to log PostgreSQL queries with transaction:
But, when changing data:
Transaction is not used as shown below:
If you don’t override changeform_view()
as shown below:
# "store/admin.py"
from django.contrib import admin
from .models import Person
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
pass
Then, change data:
Transaction is used as shown below: