Django管理员:覆盖删除方法

Django管理员:覆盖删除方法,django,django-admin,Django,Django Admin,我的admin.py如下所示: class profilesAdmin(admin.ModelAdmin): list_display = ["type","username","domain_name"] 现在,我想在删除对象之前执行一些操作: class profilesAdmin(admin.ModelAdmin): list_display = ["type","username","domain_name"] @receiver(pre_del

我的admin.py如下所示:

  class profilesAdmin(admin.ModelAdmin):
     list_display = ["type","username","domain_name"]
现在,我想在删除对象之前执行一些操作:

  class profilesAdmin(admin.ModelAdmin):
     list_display = ["type","username","domain_name"]

     @receiver(pre_delete, sender=profile)
     def _profile_delete(sender, instance, **kwargs):
        filename=object.profile_name+".xml"
        os.remove(os.path.join(object.type,filename))
如果我使用像这样的删除信号方法,我会得到一个错误,说
self
应该是第一个参数

如何修改上述功能?
我想检索被删除对象的配置文件名称。如何做到这一点

我还尝试重写delete_model方法:

def delete_model(self, request, object):
    filename=object.profile_name+".xml"
    os.remove(os.path.join(object.type,filename))
    object.delete()

但是,如果必须一次删除多个对象,则此方法不起作用。

您使用的
delete\u model
方法是正确的。当django管理员一次对多个对象执行操作时,它使用。但是,正如您在文档中看到的,这些操作仅在数据库级别使用SQL执行

您需要将
delete_model
方法添加到django admin中

def delete_model(modeladmin, request, queryset):
    for obj in queryset:
        filename=obj.profile_name+".xml"
        os.remove(os.path.join(obj.type,filename))
        obj.delete()
然后将函数添加到modeladmin中-

class profilesAdmin(admin.ModelAdmin):
    list_display = ["type","username","domain_name"]
    actions = [delete_model]
你的方法应该是

class profilesAdmin(admin.ModelAdmin):
    #...

    def _profile_delete(self, sender, instance, **kwargs):
        # do something

    def delete_model(self, request, object):
        # do something

您应该在每个方法签名(通常称为
self
)中添加对当前对象的引用作为第一个参数。此外,delete_模型应该作为一种方法来实现。

主要问题是Django管理员的批量删除使用SQL,而不是instance.delete(),如其他地方所述。对于仅限管理员的解决方案,以下解决方案保留Django管理员的“do you real want delete this”(是否真的要删除这些)间隙

最通用的解决方案是覆盖模型管理器返回的queryset以拦截delete

from django.contrib.admin.actions import delete_selected

class BulkDeleteMixin(object):
    class SafeDeleteQuerysetWrapper(object):
        def __init__(self, wrapped_queryset):
            self.wrapped_queryset = wrapped_queryset

        def _safe_delete(self):
            for obj in self.wrapped_queryset:
                obj.delete()

        def __getattr__(self, attr):
            if attr == 'delete':
                return self._safe_delete
            else:
                return getattr(self.wrapped_queryset, attr)

        def __iter__(self):
            for obj in self.wrapped_queryset:
                yield obj

        def __getitem__(self, index):
            return self.wrapped_queryset[index]

        def __len__(self):
            return len(self.wrapped_queryset)

    def get_actions(self, request):
        actions = super(BulkDeleteMixin, self).get_actions(request)
        actions['delete_selected'] = (BulkDeleteMixin.action_safe_bulk_delete, 'delete_selected', ugettext_lazy("Delete selected %(verbose_name_plural)s"))
        return actions

    def action_safe_bulk_delete(self, request, queryset):
        wrapped_queryset = BulkDeleteMixin.SafeDeleteQuerysetWrapper(queryset)
        return delete_selected(self, request, wrapped_queryset)

class SomeAdmin(BulkDeleteMixin, admin.ModelAdmin):
    ...

您尝试重写delete_model方法失败,因为当您删除多个对象时,django使用
QuerySet.delete()
,出于效率原因,您的模型的
delete()
方法将不会被调用

你可以在那里看到它
注意开始警告

Admin
delete\u model()
与模型的
delete()

因此,当您删除多个对象时,将永远不会调用自定义的delete方法

你有两条路

1.自定义删除操作。
为每个选定项调用Model.delete()操作

2.使用信号。
您可以单独使用信号,而不是在类内部

您还可以观看此问题

您可以使用从开始的用于批量删除对象,使用用于单个删除。这两种方法都将在删除对象之前处理某些内容

ModelAdmin.delete_queryset(请求,queryset)
这是关于in of的解释

delete_queryset()方法提供了HttpRequest和要删除的对象的queryset。重写此方法以自定义“删除选定对象”的删除过程

让我们看看它的作用,您可以覆盖admin。通过包含函数以这种方式初始化。在这里,您将获得对象列表,
queryset.delete()
mean一次删除所有对象,或者您可以添加一个循环来逐个删除

def delete_queryset(self, request, queryset):
    print('==========================delete_queryset==========================')
    print(queryset)

    """
    you can do anything here BEFORE deleting the object(s)
    """

    queryset.delete()

    """
    you can do anything here AFTER deleting the object(s)
    """

    print('==========================delete_queryset==========================')
所以我要从“选择窗口”中删除5个对象,这是这5个对象

然后你会像这样重定向到确认页面

记住“是的,我确定”按钮,我稍后会解释。当您单击该按钮时,您将在删除这5个对象后看到下图

这是终端输出

因此,您将以QuerySet列表的形式获取这5个对象,在删除之前,您可以在注释区域中执行任何您想要的操作

ModelAdmin.delete_模型(请求,obj)
这是关于的解释

HttpRequest和一个模型实例给出了delete_模型方法。重写此方法允许执行删除前或删除后操作。调用super().delete_model()以使用model.delete()删除对象

让我们看看它的作用,您可以覆盖admin。通过包含函数以这种方式初始化

actions = ['delete_model']

def delete_model(self, request, obj):
    print('============================delete_model============================')
    print(obj)

    """
    you can do anything here BEFORE deleting the object
    """

    obj.delete()

    """
    you can do anything here AFTER deleting the object
    """

    print('============================delete_model============================')
我只需单击我的第6个对象即可从“更改窗口”中删除

还有一个删除按钮,当你点击它时,你会看到我们之前看到的窗口

单击“是,我确定”按钮删除单个对象。您将看到以下窗口,其中包含已删除对象的通知

这是终端输出

因此,您将以单个QuerySet的形式获取选定对象,在删除之前,您可以在注释区域中执行任何您想要的操作


最后的结论是,您可以通过使用和在Django管理站点的“选择窗口”或“更改窗口”中单击“是,我确定”按钮来处理删除事件。这样我们就不需要处理像或这样的信号

这是完整的代码

from django.contrib import admin

from . import models

class AdminInfo(admin.ModelAdmin):
    model = models.AdminInfo
    actions = ['delete_model']

    def delete_queryset(self, request, queryset):
        print('========================delete_queryset========================')
        print(queryset)

        """
        you can do anything here BEFORE deleting the object(s)
        """

        queryset.delete()

        """
        you can do anything here AFTER deleting the object(s)
        """

        print('========================delete_queryset========================')

    def delete_model(self, request, obj):
        print('==========================delete_model==========================')
        print(obj)

        """
        you can do anything here BEFORE deleting the object
        """

        obj.delete()

        """
        you can do anything here AFTER deleting the object
        """

        print('==========================delete_model==========================')

admin.site.register(models.AdminInfo, AdminInfo)

但我还是得到了错误自我没有定义不,那是不可能的。如果我添加self,我会得到一个错误_profile_delete接受3个参数(给定2个),如果只删除一个对象,则会抛出一个错误。给出错误“U配置文件”对象不可编辑。此外,“操作”列表将有2个值。一个是delete_model,另一个是delete selected profiles。是的,您需要一个函数用于modeladmin操作,另一个用于单个对象(我认为您已经有了该函数)。在操作列表中有两个操作有问题吗?是的,所以我写了一个函数从列表中删除额外的操作。所以它现在可以正常工作了。Thanx
delete\u model
覆盖单个对象的删除操作,对于查询集,必须覆盖
delete\u queryset
您的回答确实帮助了我..谢谢
delete\u queryset
工作!谢谢@user578386欢迎您!不客气@guilhermia@KushanGunasekera,我想在根据某些条件删除对象之前引发异常并显示一些错误消息。如果我这样做,我会收到两条消息:我的错误消息+对象删除成功。你能帮我怎么做吗?