您可以使用下面的retry()重试Django 管理员0 次或更多次,间隔秒数为 0 或更多:
# "store/admin.py"
from django.db import DatabaseError, IntegrityError, transaction, router
from django.contrib import messages, admin
from django.shortcuts import redirect
from time import sleep
from .models import Person
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
csrf_protect_m = method_decorator(csrf_protect)
def retry(count, interval=1):
def _retry(func):
def core(*args, **kwargs):
nonlocal count
if callable(count):
count = 2
for i in range(count+1):
try:
return func(*args, **kwargs)
except DatabaseError as e:
print(e)
if i == count:
messages.error(args[1], "Error occurred, try again!")
return redirect("/".join(args[1].path.split('/')[0:4]))
sleep(interval)
return core
if callable(count):
return _retry(count)
return _retry
# ...
然后,使用@retry(4, 2)被覆盖的changeform_view()除了每次异常发生时正常尝试之外,还可以重试添加和更改数据 4 次,间隔为 2 秒,如下所示:
# "store/admin.py"
from django.db import DatabaseError, IntegrityError, transaction, router
from django.contrib import messages, admin
from django.shortcuts import redirect
from time import sleep
from .models import Person
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
csrf_protect_m = method_decorator(csrf_protect)
def retry(count, interval=1):
# ...
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@retry(4, 2) # Here
@csrf_protect_m
def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
with transaction.atomic(using=router.db_for_write(self.model)):
return self._changeform_view(request, object_id, form_url, extra_context)
所以,让我们提出IntegrityError异常在覆盖的response_add()和response_change()如下所示:
# ...
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@retry(4, 2) # Here
@csrf_protect_m
def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
with transaction.atomic(using=router.db_for_write(self.model)):
return super()._changeform_view(request, object_id, form_url, extra_context)
def response_add(self, request, obj, post_url_continue=None):
raise IntegrityError("Exception occurs") # Here
return super().response_add(request, obj, post_url_continue)
def response_change(self, request, obj):
raise IntegrityError("Exception occurs") # Here
return super().response_change(request, obj)
现在,如果尝试添加数据:
添加数据除了正常尝试外还会重试 4 次,如下所示:
Exception occurs # Normal try
Exception occurs # 1st retry
Exception occurs # 2st retry
Exception occurs # 3rd retry
Exception occurs # 4th retry
[30/Dec/2022 22:01:41] "POST /admin/store/person/add/ HTTP/1.1" 302 0
[30/Dec/2022 22:01:41] "GET /admin/store/person HTTP/1.1" 301 0
[30/Dec/2022 22:01:41] "GET /admin/store/person/ HTTP/1.1" 200 21364
[30/Dec/2022 22:01:41] "GET /admin/jsi18n/ HTTP/1.1" 200 3195
最后,页面被重定向到“选择更改”页面不添加数据如下图:
接下来,如果尝试将数据从 John 更改为 David:
除了正常尝试之外,更改数据还会重试 4 次,如下所示:
Exception occurs # Normal try
Exception occurs # 1st retry
Exception occurs # 2st retry
Exception occurs # 3rd retry
Exception occurs # 4th retry
[30/Dec/2022 23:02:49] "POST /admin/store/person/678/change/ HTTP/1.1" 302 0
[30/Dec/2022 23:02:49] "GET /admin/store/person HTTP/1.1" 301 0
[30/Dec/2022 23:02:50] "GET /admin/store/person/ HTTP/1.1" 200 22512
[30/Dec/2022 23:02:50] "GET /admin/jsi18n/ HTTP/1.1" 200 3195
最后,页面被重定向到“选择更改”页面不改变数据如下所示:
接下来,使用@retry被覆盖的delete_view()每次出现异常时,除了正常尝试之外,默认可以重试2次删除数据,间隔1秒,如下图:
# "store/admin.py"
from django.db import DatabaseError, IntegrityError, transaction, router
from django.contrib import messages, admin
from django.shortcuts import redirect
from time import sleep
from .models import Person
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
csrf_protect_m = method_decorator(csrf_protect)
def retry(count, interval=1):
# ...
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@retry # Here
@csrf_protect_m
def delete_view(self, request, object_id, extra_context=None):
with transaction.atomic(using=router.db_for_write(self.model)):
return self._delete_view(request, object_id, extra_context)
所以,让我们提出IntegrityError异常在被覆盖的response_delete()如下所示:
# ...
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@retry # Here
@csrf_protect_m
def delete_view(self, request, object_id, extra_context=None):
with transaction.atomic(using=router.db_for_write(self.model)):
return super()._delete_view(request, object_id, extra_context)
def response_delete(self, request, obj_display, obj_id):
raise IntegrityError("Exception occurs") # Here
return super().response_delete(request, obj_display, obj_id)
现在,如果点击删除在“更改”页面:
然后点击是,我确定尝试删除数据:
除了正常尝试之外,删除数据还会重试 2 次,如下所示:
Exception occurs # Normal try
Exception occurs # 1st retry
Exception occurs # 2st retry
[30/Dec/2022 23:30:30] "POST /admin/store/person/680/delete/ HTTP/1.1" 302 0
[30/Dec/2022 23:30:30] "GET /admin/store/person HTTP/1.1" 301 0
[30/Dec/2022 23:30:30] "GET /admin/store/person/ HTTP/1.1" 200 22513
[30/Dec/2022 23:30:31] "GET /admin/jsi18n/ HTTP/1.1" 200 3195
最后,页面被重定向到“选择更改”页面不删除数据如下图:
最后,使用@retry被覆盖的delete_queryset()每次出现异常时,除了正常尝试之外,默认可以重试删除数据2次,间隔1秒,如下图。默认,交易不用于Django 管理操作:
# "store/admin.py"
from django.db import DatabaseError, IntegrityError, transaction, router
from django.contrib import messages, admin
from django.shortcuts import redirect
from time import sleep
from .models import Person
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
csrf_protect_m = method_decorator(csrf_protect)
def retry(count, interval=1):
# ...
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@retry # Here
@transaction.atomic
def delete_queryset(self, request, queryset):
queryset.delete()
所以,让我们提出IntegrityError异常在被覆盖的delete_queryset()如下所示:
# ...
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
@retry # Here
@transaction.atomic
def delete_queryset(self, request, queryset):
queryset.delete()
raise IntegrityError("Exception occurs") # Here
现在,如果点击走在“更改”页面在“选择更改”页面:
然后点击是,我确定尝试删除数据:
删除数据除了正常尝试外还会重试 2 次,如下所示:
Exception occurs # Normal try
Exception occurs # 1st retry
Exception occurs # 2st retry
[31/Dec/2022 00:18:54] "POST /admin/store/person/ HTTP/1.1" 302 0
[31/Dec/2022 00:18:55] "GET /admin/store/person/ HTTP/1.1" 200 23013
[31/Dec/2022 00:18:55] "GET /admin/jsi18n/ HTTP/1.1" 200 3195
最后,页面被重定向到“选择更改”页面没有删除数据,但我不知道如何删除默认消息“已成功删除 2 人”。如下所示:
另外,如果使用@retry默认0.5间隔秒重试3次,需要分别将count = 2改为count = 3,将interval=1改为interval=0.5,如下图:
# "store/admin.py"
# ...
# ↓ Here
def retry(count, interval=0.5):
def _retry(func):
def core(*args, **kwargs):
nonlocal count
if callable(count):
count = 3 # <= Here
for i in range(count+1):
try:
return func(*args, **kwargs)
except DatabaseError as e:
print(e)
if i == count:
messages.error(args[1], "Error occurred, try again!")
return redirect("/".join(args[1].path.split('/')[0:4]))
sleep(interval)
return core
if callable(count):
return _retry(count)
return _retry
# ...