【问题标题】:Is there a way to override the delete_selected method in ModelAdmin but keep confirmation?有没有办法覆盖 ModelAdmin 中的 delete_selected 方法但保持确认?
【发布时间】:2019-10-20 09:41:38
【问题描述】:

我有:

class Person(admin.ModelAdmin):
    actions = ['delete_selected']
    def delete_selected(modeladmin, request, queryset):
        # Show confirmation page.
        for obj in queryset:
            obj.custom_delete()

我留下的那条评论是我苦苦挣扎的地方。我仍然想在执行自定义删除之前显示确认页面。

【问题讨论】:

    标签: django django-rest-framework django-admin


    【解决方案1】:

    简答:您应该覆盖delete_queryset [Django-doc],因为它封装了移除对象的真实逻辑。

    您应该覆盖delete_selected。这个动作是defined like [GitHub]

    def delete_selected(modeladmin, request, queryset):
    
        # ...
    
        # Populate deletable_objects, a data structure of all related objects that
        # will also be deleted.
        deletable_objects, model_count, perms_needed, protected = modeladmin.get_deleted_objects(queryset, request)
    
        # The user has already confirmed the deletion.
        # Do the deletion and return None to display the change list view again.
        if request.POST.get('post') and not protected:
            if perms_needed:
                raise PermissionDenied
            n = queryset.count()
            if n:
                for obj in queryset:
                    obj_display = str(obj)
                    modeladmin.log_deletion(request, obj, obj_display)
                modeladmin.delete_queryset(request, queryset)
                modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % {
                    "count": n, "items": model_ngettext(modeladmin.opts, n)
                }, messages.SUCCESS)
            # Return None to display the change list page again.
            return None
    
        # ...
    
        context = {
            # ...
        }
    
        request.current_app = modeladmin.admin_site.name
    
        # Display the confirmation page
        return TemplateResponse(request, modeladmin.delete_selected_confirmation_template or [
            "admin/%s/%s/delete_selected_confirmation.html" % (app_label, opts.model_name),
            "admin/%s/delete_selected_confirmation.html" % app_label,
            "admin/delete_selected_confirmation.html"
        ], context)
    
    
    delete_selected.allowed_permissions = ('delete',)
    delete_selected.short_description = gettext_lazy("Delete selected %(verbose_name_plural)s")

    这里的关键部分是此操作将执行正确的检查,但删除本身是通过调用完成的:

                modeladmin.delete_queryset(request, queryset)

    因此,改写 delete_queryset 就足够了:

    class PersonAdmin(admin.ModelAdmin):
    
        actions = ['delete_selected']
    
        def delete_queryset(self, request, queryset):
            for obj in queryset:
                obj.custom_delete()

    ModelAdmin 有一个standard implementation for delete_queryset [GitHub]

    class ModelAdmin(BaseModelAdmin):
    
        # ...
    
        def delete_queryset(self, request, queryset):
            """Given a queryset, delete it from the database."""
            queryset.delete()

    【讨论】:

    • 如果修改了delete_query集以避免删除某些对象,那么delete_selected中的消息就没有意义了,因为实际上被删除的obj会更少。有没有办法修改消息?
    【解决方案2】:

    我的要求有点不同。我必须拦截 delete_selected 操作并根据条件显示错误。这就是我所做的 -

    在模型管理中

    @admin.register(Model)
    class ModelAdmin(model.Admin):
        ...
        def get_actions(self, request):
            actions = super().get_actions(request)        
            self.actions.append(delete_selected)
            self.actions.append(...otheractions)
            return actions
    

    在模型管理员之外

    #Import goes to top of the file
    from django.contrib.admin.actions import delete_selected as default_delete_selected
    
    def delete_selected(modeladmin, request, queryset):
        response = HttpResponseRedirect(request.get_full_path())    
        #logic to validate
        for obj in queryset:
            if obj.name == 'test':
               messages.error(request,'error message')
               return response
        return default_delete_selected(modeladmin, request, queryset)
    

    【讨论】:

    • 它对我有帮助,但如果有人需要它。以下是剩下的导入:from django.contrib import messages 和 from django.http import HttpResponseRedirect
    猜你喜欢
    • 2020-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-15
    • 2013-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多