Django admin:覆盖删除方法

arj*_*jun 17 django django-admin

我有admin.py如下:

  class profilesAdmin(admin.ModelAdmin):
     list_display = ["type","username","domain_name"]
Run Code Online (Sandbox Code Playgroud)

现在我想在删除对象之前执行一些操作:

  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))
Run Code Online (Sandbox Code Playgroud)

如果我使用像这样的删除信号方法我得到一个错误说self应该是第一个参数.

如何修改上述功能?
我想检索被删除对象的profile_name.如何才能做到这一点?

我也尝试重写delete_model方法:

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

但如果必须一次删除多个对象,这不起作用.

Kus*_*era 19

您可以使用delete_queryset这是来自Django的2.1起批量删除对象和delete_model单删除。这两种方法都会在删除对象之前处理一些事情。

ModelAdmin.delete_queryset(request, queryset)


这是关于解释delete_queryset发行说明的Django 2.1

delete_queryset() 方法被赋予 HttpRequest 和要删除的对象的 QuerySet。覆盖此方法以自定义“删除选定对象”的删除过程

让我们看看delete_queryset做了什么,你可以覆盖 admin。ModelAdmin类以这种方式包含delete_queryset函数。在这里你会得到对象列表,queryset.delete()意思是一次删除所有对象,或者你可以添加一个循环来一个一个地删除。

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==========================')
Run Code Online (Sandbox Code Playgroud)

所以我要从“选择窗口”中删除 5 个对象,这是这 5 个对象。

从“选择窗口”中删除 5 个对象

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

将删除这 5 个对象

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

成功删除 5 个对象

这是终端输出,

这 5 个对象的终端输出

所以你会得到这 5 个对象作为 QuerySet 的列表,在删除之前你可以在评论区做任何你想做的事情。

ModelAdmin.delete_model(request, obj)


这是关于delete_model的解释。

delete_model 方法被赋予了 HttpRequest 和一个模型实例。覆盖此方法允许执行删除前或删除后操作。调用 super().delete_model() 以使用 Model.delete() 删除对象。

让我们看看delete_model做了什么,你可以覆盖admin。ModelAdmin类以这种方式包含delete_model函数。

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============================')
Run Code Online (Sandbox Code Playgroud)

我只需单击我的第 6 个对象即可从“更改窗口”中删除。

从“更改窗口”中删除 1 个对象

还有另一个删除按钮,当您单击它时,您将看到我们之前看到的窗口。

将删除那些 1 个对象

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

成功删除 1 个对象

这是终端输出,

这 1 个对象的终端输出

因此,您将获得所选对象作为 QuerySet 的单个对象,并且在删除之前您可以在评论区中做任何您想做的事情。


最后的结论是,你可以通过点击“是的,我确定”,在“选择窗口”,“变更窗口”在Django管理站点按钮或使用处理删除事件delete_querysetdelete_model。这样我们就不需要处理像django.db.models.signals.pre_deletedjango.db.models.signals.post_delete这样的信号。

这是完整的代码,

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)
Run Code Online (Sandbox Code Playgroud)

  • 你的回答对我很有帮助..谢谢 (2认同)

Aid*_*wen 11

您使用自己的delete_model方法走在正确的轨道上.当django admin立即对多个对象执行操作时,它使用更新功能.但是,正如您在文档中看到的那样,这些操作仅在数据库级别使用SQL执行.

您需要在django admin 中将您的delete_model方法添加为自定义操作.

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()
Run Code Online (Sandbox Code Playgroud)

然后将您的功能添加到您的modeladmin -

class profilesAdmin(admin.ModelAdmin):
    list_display = ["type","username","domain_name"]
    actions = [delete_model]
Run Code Online (Sandbox Code Playgroud)


Sco*_*t A 5

主要问题是Django管理员的批量删除使用SQL,而不是instance.delete(),如其他地方所述.对于仅限管理员的解决方案,以下解决方案保留了Django管理员的"你真的想删除这些"插页式广告.

最通用的解决方案是覆盖模型管理器返回的查询集以拦截删除.

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):
    ...
Run Code Online (Sandbox Code Playgroud)