如何重写模型的delete()方法并支持相关删除

34 投票
9 回答
76813 浏览
提问于 2025-04-15 14:54

我遇到了一个问题,我通过调用 some_widget_instance.delete() 来删除一个 Widget。同时,我有一个叫 WidgetFile 的模型,它有一个重写的 delete() 方法,这样当删除 WidgetFile 时,我可以把硬盘上的文件也删除掉。问题是,当我删除一个 Widget 时,如果它有相关的 WidgetFiles,像这样:

class WidgetFile(models.Model):

    widget = models.ForeignKey(Widget)

那么,当我删除这个 Widget 时,它的 WidgetFiles 会被删除,但重写的 delete() 方法并没有被触发,所以我在硬盘上做的那些额外操作没有执行。非常感谢任何帮助。

9 个回答

4

在删除之前使用 clear(),可以把相关对象集合中的所有对象都移除。

可以参考这个链接了解更多内容:django-following-relationships-backward

示例:

group.link_set.clear() 
group.delete() 
83

我正在做同样的事情,注意到Django文档里有个小提示,你应该考虑一下。

重写预定义的模型方法

重写删除 注意,当使用QuerySet批量删除对象时,并不一定会调用对象的delete()方法。为了确保自定义的删除逻辑能够执行,你可以使用pre_delete和/或post_delete信号。

这意味着你的代码片段并不总是能如你所愿。使用信号来处理删除操作会是更好的选择。

我选择了以下方法:

import shutil
from django.db.models.signals import pre_delete 
from django.dispatch import receiver

@receiver(pre_delete)
def delete_repo(sender, instance, **kwargs):
    if sender == Set:
        shutil.rmtree(instance.repo)
47

我搞明白了。我在那个 Widget 模型上加了这个:

def delete(self):
    files = WidgetFile.objects.filter(widget=self)
    if files:
        for file in files:
            file.delete()
    super(Widget, self).delete()

这样就会让每个相关的对象都执行必要的 delete() 方法,从而触发我自定义的文件删除代码。是的,这样对数据库的开销会更大,但如果你本来就是要删除硬盘上的文件,额外多访问几次数据库其实也没那么大的负担。

撰写回答