[Answered ]-Overwrite django admin delete_queryset's "short_description"

1👍

I finally figured it out.

It involves some explanations from this other question and this.

To sum it up (I don’t understand it completly), it seems that the delete_selected is the action called and that the delete_queryset is the real function doing the job of the deletion. But as the delete_queryset is defined outside of the model (and then defined globally on your app), you can’t subclass it in your ModelAdmin.

I first tried to do something like this :

class MyAdminModel(admin.ModelAdmin):
    def get_actions(self, request):
        actions = super().get_actions(request)
        function, name, _short_description = actions['delete_selected']
        short_description = "I want this custom description"
        function.short_description = short_description
        return actions

But you can easily see that this will change the description globally.

So the trick would be instead to make a deep copy of the function and add it to the actions. I have been using this other answer to do the job.

So, this would at last give something like this :

from django.contrib import admin
from django.db import transaction
from .models import MyModel
import types

def copy_func(f, name=None):
    '''
    return a function with same code, globals, defaults, closure, and 
    name (or provide a new name)
    '''
    fn = types.FunctionType(f.__code__, f.__globals__, name or f.__name__,
        f.__defaults__, f.__closure__)
    # in case f was given attrs (note this dict is a shallow copy):
    fn.__dict__.update(f.__dict__) 
    return fn

@admin.register(MyModel)
class MyAdminModel(admin.ModelAdmin):

    def delete_queryset(self, request, queryset):
        """
        You can there rewrite wathever you want in the original function, for 
        instance: here apply "delete" on each instance
        """
       with transaction.atomic():
           for obj in queryset:
               obj.delete()

    def get_actions(self, request):
        actions = super().get_actions(request)
        name = "delete_selected"
        function, name, _short_description = actions[name]
        my_custom_delete_selected = copy_func(function, name)
        short_description = "Supprimer définitivement les signalements sélectionnés"
        del actions[name]
        actions[name] = (my_custom_delete_selected, name, short_description)
        return actions

Edit :

This seems to work only if the name of the "delete_selected" function stays unchanged. Otherwise the confirmation form will return something like a "no chosen action" message instead of performing the deletion (the message might be a tad different, my django is using french messages).

Leave a comment