有没有一种方法可以覆盖ModelAdmin中的delete_selected方法,但要进行确认?

时间:2019-06-04 20:36:01

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

我有:

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

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

2 个答案:

答案 0 :(得分:3)

我的要求有些不同。我不得不拦截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)

答案 1 :(得分:2)

简短答案:您应该覆盖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(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()