【问题标题】:How to retry when exception occurs in Django Admin?Django Admin出现异常时如何重试?
【发布时间】:2022-12-31 00:45:48
【问题描述】:

如果发生异常,我想重试Django 管理员:

  1. 尝试添加数据时:

    1. 尝试更改数据时:

    1. 点击时删除“更改”页面:

    然后点击是,我确定尝试删除数据:

    1. 点击时“选择更改”页面:

    然后点击是,我确定尝试删除数据:

    我有Person模特以下:

    # "store/models.py"
    
    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=30)
    

    和,Person管理员以下:

    # "store/admin.py"
    
    from django.contrib import admin
    from .models import Person
    
    @admin.register(Person)
    class PersonAdmin(admin.ModelAdmin):
        pass
    

    那么,当发生异常时我该如何重试Django 管理员

【问题讨论】:

    标签: python django exception django-admin django-admin-actions


    【解决方案1】:

    您可以使用下面的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
    
    # ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-25
      • 2015-08-08
      • 1970-01-01
      • 2021-12-30
      • 2015-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多