Is there a way to override the delete_selected method in ModelAdmin but keep confirmation?

后端 未结 2 828
一向
一向 2021-01-13 13:48

I have:

class Person(admin.ModelAdmin):
    actions = [\'delete_selected\']
    def delete_selected(modeladmin, request, queryset):
        # Show confirmati         


        
相关标签:
2条回答
  • 2021-01-13 14:33

    My requirement was a bit different. I had to intercept the delete_selected action and display error depending on the condition. This is what I did -

    In Model Admin

    @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
    

    Outside the Model admin

    #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)
    
    0 讨论(0)
  • 2021-01-13 14:35

    Short answer: you should override delete_queryset [Django-doc], since this encapsulates the real logic to remove the objects.

    You should not override delete_selected. This action is 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")

    The key part here is that this action will perform the proper checks, but the deletion itself is done through a call:

                modeladmin.delete_queryset(request, queryset)

    So it is sufficient to override delete_queryset instead, with:

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

    A ModelAdmin has a 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()
    0 讨论(0)
提交回复
热议问题