我重写了Django的模型删除方法,以便删除磁盘中用于图像字段的孤立文件,如下所示:
class Image(models.Model):
img = models.ImageField(upload_to=get_image_path)
...
def delete(self, *args, **kwargs):
self.img.delete()
super(Image, self).delete(*args, **kwargs)
当我从管理员中删除单个对象时这很好用,但是当我选择多个对象并删除它们时,这似乎不会被调用。我已经谷歌搜索了一段时间,但没有找到合适的关键字来获得答案,官方文档似乎也没有谈论这个主题。
答案 0 :(得分:33)
delete()方法执行批量删除,并且不会在模型上调用任何delete()方法。但是,它会为所有已删除的对象(包括级联删除)发出pre_delete和post_delete信号。
要使其正常工作,您可以覆盖QuerySet
上的删除方法,然后将QuerySet
应用为经理:
class ImageQuerySet(models.QuerySet):
def delete(self, *args, **kwargs):
for obj in self:
obj.img.delete()
super(ImageQuerySet, self).delete(*args, **kwargs)
class Image(models.Model):
objects = ImageQuerySet.as_manager()
img = models.ImageField(upload_to=get_image_path)
...
def delete(self, *args, **kwargs):
self.img.delete()
super(Image, self).delete(*args, **kwargs)
答案 1 :(得分:7)
queryset的删除方法直接在数据库上工作。它不会调用Model.delete()
方法。来自docs:
请记住,只要有可能,这将完全在SQL中执行,因此在此过程中不一定会调用各个对象实例的delete()方法。如果您在模型类上提供了自定义delete()方法并希望确保调用它,则需要“手动”删除该模型的实例(例如,通过迭代QuerySet并调用delete()on每个对象单独使用)而不是使用QuerySet的批量delete()方法。
如果要覆盖Django管理界面的默认行为,可以编写自定义delete
操作:
https://docs.djangoproject.com/en/1.7/ref/contrib/admin/actions/
另一种方法是覆盖post_delete
(或pre_delete
)信号,而不是delete
方法:
https://docs.djangoproject.com/en/1.7/ref/signals/#django.db.models.signals.post_delete
与pre_delete类似,但在模型的delete()方法和queryset的delete()方法结束时发送。
答案 2 :(得分:0)
我相信docs
中已解决了此问题它说:
在批量操作中不会调用覆盖的模型方法
请注意,使用QuerySet批量删除对象或级联删除操作时,不必调用对象的delete()方法。为了确保执行自定义的删除逻辑,您可以使用pre_delete和/或post_delete信号。
不幸的是,批量创建或更新对象时没有解决方法,因为没有调用save(),pre_save和post_save。
如以上文档中所建议,我相信更好的解决方案是使用post_delete
信号,如下所示:
from django.db.models.signals import post_delete
from django.dispatch import receiver
class Image(models.Model):
img = models.ImageField(upload_to=get_image_path)
...
@receiver(post_delete, sender=Image)
def delete_image_hook(sender, instance, using, **kwargs):
instance.img.delete()
与覆盖delete
方法不同的是,delete_image_hook
函数也应在批量删除和级联删除时调用。以下是有关使用Django的信号的更多信息:https://docs.djangoproject.com/en/1.11/topics/signals/#connecting-to-signals-sent-by-specific-senders
关于先前答案的说明:
之前的一些帖子建议重写QuerySet的delete
方法,这可能会影响性能和其他意外行为。也许这些答案是在实施Django的Signals之前写的,但是我认为使用Signals是一种更干净的方法。