Django admin:覆盖删除方法

时间:2013-03-04 07:09:06

标签: 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_delete, sender=profile)
     def _profile_delete(sender, instance, **kwargs):
        filename=object.profile_name+".xml"
        os.remove(os.path.join(object.type,filename))

如果我使用这样的删除信号方法,我会收到错误,说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()

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

5 个答案:

答案 0 :(得分:9)

您使用delete_model方法走在正确的轨道上。当django管理员一次对多个对象执行操作时,它会使用update function。但是,正如您在文档中看到的那样,这些操作仅在数据库级别使用SQL执行。

您需要将delete_model方法作为custom action添加到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]

答案 1 :(得分: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):
    ...

答案 2 :(得分:1)

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

你可以在https://docs.djangoproject.com/en/1.9/ref/contrib/admin/actions/看到它 观看开始警告

管理员delete_model()与模型的delete()相同 https://github.com/django/django/blob/master/django/contrib/admin/options.py#L1005

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

你有两种方式。

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

2.使用信号。
你可以单独使用信号,而不是在课堂内。

您还可以观看此问题Django model: delete() not triggered

答案 3 :(得分:0)

你的方法应该是

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

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

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

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

答案 4 :(得分:0)

您可以将delete_queryset之后的Django 2.1用于批量删除对象,将delete_model用于单个删除。这两种方法在删除对象之前都会处理一些事情。

ModelAdmin.delete_queryset(请求,查询集)


这是delete_querysetrelease note中有关Django 2.1的解释。

  

为delete_queryset()方法提供了HttpRequest和要删除的对象的QuerySet。覆盖此方法可自定义“删除所选对象”的删除过程

让我们看看delete_queryset的功能,您可以通过包含ModelAdmin函数,以这种方式覆盖admin。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==========================')

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

deleting 5 objects from "select window"

然后,您将像这样重定向到确认页面

going to delete those 5 objects

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

successfully deleted 5 objects

这是终端输出,

terminal output of those 5 objects

因此,您将获得这5个对象作为QuerySet的列表,并且在删除之前,您可以在注释区域中执行任何所需的操作。

ModelAdmin.delete_model(request,obj)


这是关于delete_model的说明。

  

为delete_model方法提供了HttpRequest和一个模型实例。重写此方法可以执行删除前或删除后的操作。调用super()。delete_model()以使用Model.delete()删除对象。

让我们看看delete_model的功能,您可以通过包含ModelAdmin函数,以这种方式覆盖admin。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============================')

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

deleting 1 object from "change window"

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

going to delete those 1 object

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

successfully deleted 1 object

这是终端输出,

terminal output of those 1 object

因此,您将选择的对象作为QuerySet的一个,而在删除之前,您可以在注释区域中执行任何所需的操作。


最终结论是您可以通过使用{{3}单击Django Admin Site中“选择窗口”或“更改窗口”中的“是,我确定”按钮来处理删除事件。 }和delete_queryset。这样,我们就不需要处理delete_modeldjango.db.models.signals.pre_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)