我的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()
但如果必须一次删除多个对象,这不起作用。
答案 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用于单个删除。这两种方法在删除对象之前都会处理一些事情。
这是delete_queryset的release 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个对象。
然后,您将像这样重定向到确认页面
请注意“是的,我确定”按钮,稍后再解释。当您单击该按钮时,删除这5个对象后,您将看到下图。
这是终端输出,
因此,您将获得这5个对象作为QuerySet的列表,并且在删除之前,您可以在注释区域中执行任何所需的操作。
这是关于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============================')
我只需单击我的第六个对象即可从“更改窗口”中删除。
还有另一个“删除”按钮,当您单击它时,您将看到我们之前看到的窗口。
单击“是,我确定”按钮以删除单个对象。您将看到以下窗口,其中包含该已删除对象的通知。
这是终端输出,
因此,您将选择的对象作为QuerySet的一个,而在删除之前,您可以在注释区域中执行任何所需的操作。
最终结论是您可以通过使用{{3}单击Django Admin Site中“选择窗口”或“更改窗口”中的“是,我确定”按钮来处理删除事件。 }和delete_queryset。这样,我们就不需要处理delete_model或django.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)