Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have:

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

That comment I left there is where I'm struggling. I still want to show the confirmation page before I perform my custom delete.

like image 449
Pittfall Avatar asked Dec 10 '22 02:12

Pittfall


2 Answers

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()
like image 200
Willem Van Onsem Avatar answered May 26 '23 17:05

Willem Van Onsem


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)
like image 24
Manju Prabhu Avatar answered May 26 '23 17:05

Manju Prabhu