我正在Django中构建一个Web应用程序。我有一个上传文件的模型,但我不能删除文件。下面是我的代码:
class Song(models.Model):
name = models.CharField(blank=True, max_length=100)
author = models.ForeignKey(User, to_field='id', related_name="id_user2")
song = models.FileField(upload_to='/songs/')
image = models.ImageField(upload_to='/pictures/', blank=True)
date_upload = models.DateField(auto_now_add=True)
def delete(self, *args, **kwargs):
# You have to prepare what you need before delete the model
storage, path = self.song.storage, self.song.path
# Delete the model before the file
super(Song, self).delete(*args, **kwargs)
# Delete the file after the model
storage.delete(path)
然后,在python manage.py shell
中,我这样做:
song = Song.objects.get(pk=1)
song.delete()
它从数据库中删除记录,但不删除服务器上的文件。我还可以尝试什么?
谢谢!
9条答案
按热度按时间pkln4tw61#
在Django 1.3之前,当你删除相应的模型示例时,文件会自动从文件系统中删除。你可能使用的是较新的Django版本,所以你必须自己实现从文件系统中删除文件。
基于信号的简单示例
我在撰写本文时选择的方法是
post_delete
和pre_save
信号的混合,这使得每当删除相应的模型或更改其文件时,都会删除过时的文件。基于假设的
MediaFile
模型:save()
方法调用碰巧在一个被回滚的事务中,你的数据可能最终引用了一个不存在的文件。你可以考虑将文件删除逻辑 Package 到transaction.on_commit()
中,就像Mikhail的评论中建议的那样。save()
(例如,通过批量更新QuerySet
),则旧文件将继续存在,因为信号不会运行。如果您使用传统的文件处理方法,则不会发生这种情况。file
作为字段名,这不是一个好的样式,因为它与内置的file
对象标识符冲突。附录:定期清理
实际上,你可能还想运行一个定期任务来处理孤儿文件清理,以防运行时故障阻止某些文件被删除。考虑到这一点,你可能会完全摆脱信号处理程序,并使这样的任务成为处理不敏感数据和不那么大的文件的机制。
无论哪种方式,如果你正在处理敏感数据,最好是双重或三重检查,确保你永远不会在生产中及时删除数据,以避免任何相关的责任。
另请参见
FieldFile.delete()
(注意,它描述了FieldFile
类,但你可以直接在字段上调用.delete()
:FileField
示例代理到相应的FieldFile
示例,您可以访问它的方法,就像它们是字段的方法一样)请注意,当删除模型时,相关文件不会被删除。如果您需要清理孤立文件,则需要自己处理(例如,使用自定义管理命令,该命令可以手动运行或通过cron定期运行)。
在Django的早期版本中,当一个包含
FileField
的模型示例被删除时,FileField
也会自动从后端存储中删除该文件。这为几种数据丢失场景打开了大门,包括回滚的事务和不同模型上引用同一文件的字段。在Django 1.3中,当一个模型被删除时,FileField
的delete()
方法不会被调用。如果你需要清理孤立文件,你需要自己处理它(例如,使用一个自定义的管理命令,可以手动运行或通过cron定期运行)。pre_delete
信号的示例gr8qqesn2#
尝试django-cleanup,当您删除模型时,它会自动调用FileField上的delete方法。
settings.py
hec6srdp3#
你可以通过Django〉= 1.10调用file字段的
.delete
方法从文件系统中删除文件,如下所示:wr98u20j4#
您也可以简单地覆盖模型的删除函数,以检查文件是否存在,并在调用超级函数之前删除它。
oymdgrw75#
Django 2.x解决方案:
在Django 2中处理文件删除非常容易。我已经尝试过使用Django 2和SFTP Storage以及FTP STORAGE的以下解决方案,并且我很确定它可以与任何其他实现
delete
方法的存储管理器一起工作。(delete
方法是storage
抽象方法之一,应该从存储中删除文件,物理!)重写模型的
delete
方法,使示例在删除自身之前先删除其FileFields:它对我来说很容易。如果你想在删除之前检查文件是否存在,你可以使用
storage.exists
。例如,self.song.storage.exists(self.song.name)
将返回一个boolean
,表示歌曲是否存在。所以它看起来像这样:编辑(添加):
正如@HeyMan所提到的,使用此解决方案调用
Song.objects.all().delete()
不会删除文件!这是因为Song.objects.all().delete()
正在运行Default Manager的删除查询。因此,如果您希望能够通过使用objects
方法删除模型的文件,则必须编写并使用自定义管理器(仅用于覆盖其删除查询):并且为了将
CustomManager
分配给模型,您必须在模型中初始化objects
:现在你可以在任何
objects
子查询的末尾使用.delete()
。我写了最简单的CustomManager
,但是你可以通过返回一些关于你删除的对象或任何你想要的东西来做得更好。zhte4eai6#
这是一个应用程序,将删除旧文件,每当模型被删除或上传一个新文件:django-smartfields
esyap4oy7#
对于那些在较新版本的Django(目前为3.1)中寻找答案的人。
我找到了这个website,它对我没有任何改变,只要把它添加到你的
models.py
:nr7wwzry8#
@Anton Strogonoff
我在代码中缺少了一些东西,当一个文件改变时,如果你创建一个新文件会产生一个错误,因为是一个新文件,没有找到路径。我修改了函数的代码,并添加了一个try/except语句,它工作得很好。
fkvaft9z9#
这段代码将运行每次我上传一个新的图像(标志字段),并检查如果一个标志已经存在,如果是这样,关闭它,并将其从磁盘中删除。同样的过程当然可以在接收器功能。希望这有帮助。