覆盖 django 管理员 delete_queryset 的 "short_description"

Overwrite django admin delete_queryset's "short_description"

我一直在我的应用程序中覆盖 django 的 delete_queryset(主要是为了提供自定义批量删除)。

我找不到覆盖此方法的“short_description”的方法。

对于自定义方法,您可以轻松使用 short_description 属性,例如:

class MyAdminModel(admin.ModelAdmin):
    def dump_model(self, request, queryset):
        pass
    dump_model.short_description = "My description"

但这行不通:

class MyAdminModel(admin.ModelAdmin):
    def delete_queryset(self, request, queryset):
        pass
    delete_queryset.short_description = "My description"

我已经尝试了标准 delete_queryset 的每个 method/attribute(在 super() 调用之后的 __init__ 方法中)但没有找到任何有用的东西,尽管我可能漏掉了什么。

我也试过使用 delattr 删除标准方法(也在 __init__ 中),尽管它看起来有点笨拙。它也失败了,抛出一个 AttributeError :

class MyAdminModel(admin.ModelAdmin):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        delattr(self, "delete_queryset")

终于想通了

里面涉及到 and this的一些解释。

总结一下(我不完全理解),似乎 delete_selected 是调用的操作,而 delete_queryset 是执行删除工作的真正功能.但是由于 delete_queryset 是在模型外部定义的(然后在您的应用程序中全局定义),您不能在 ModelAdmin 中对其进行子类化。

我第一次尝试做这样的事情:

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

但是您可以很容易地看到这将全局更改描述

所以诀窍是制作函数的深层副本并将其添加到操作中。我一直在使用这个 other answer 来完成这项工作。

所以,这最终会给出这样的结果:

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

编辑:

这似乎只有在“delete_selected”函数的名称保持不变的情况下才有效。否则确认表单将 return 类似“未选择的操作”的消息而不是执行删除(该消息可能有点不同,我的 django 使用的是法语消息)。