You need to override delete_queryset() with @transaction.atomic
as shown below to run SELECT FOR UPDATE
for the default "Delete selected" in Django Admin Actions. *print(qs)
is important to run SELECT FOR UPDATE
:
# "store/admin.py"
from django.contrib import admin
from .models import Person
from django.db import transaction
from django.db import connection
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@transaction.atomic # Here
def delete_queryset(self, request, queryset):
ids = []
for obj in queryset:
ids.append(obj.id)
qs = queryset.select_for_update().filter(id__in=ids)
print(qs) # <- Important to run "SELECT FOR UPDATE"
qs.delete()
Then, when clicking Go to go to delete the selected persons as shown below:
Then, clicking Yes I'm sure to delete the selected persons:
SELECT FOR UPDATE
query and DELETE
query are run in transaction as shown below:
In addition, you can use raw queries as shown below if you want to run shorter queries:
# "store/admin.py"
from django.contrib import admin
from .models import Person
from django.db import transaction
from django.db import connection
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@transaction.atomic # Here
def delete_queryset(self, request, queryset):
ids = ()
qs_length = len(queryset)
if qs_length > 1:
for obj in queryset:
ids += (obj.id,)
ids = str(ids)
elif qs_length == 1:
ids = "(" + str(queryset[0].id) + ")"
else:
return
with connection.cursor() as cursor: # Here
query = "SELECT * FROM store_person WHERE id IN " + ids + " FOR UPDATE"
cursor.execute(query)
query = "DELETE FROM store_person WHERE id IN " + ids
cursor.execute(query)
Then, when clicking Go to go to delete the selected persons as shown below:
Then, clicking Yes I'm sure to delete the selected persons:
shorter SELECT FOR UPDATE
query and shorter DELETE
query are run in transaction as shown below:
In addition, you can check the default code of delete_queryset() which is not overridden as shown below:
class ModelAdmin(BaseModelAdmin):
# ...
def delete_queryset(self, request, queryset):
"""Given a queryset, delete it from the database."""
queryset.delete()