Django 2.x 解决方案:
在 Django 2 中处理文件删除非常简单。我已经试过使用 Django 2 和 SFTP 存储以及 FTP 存储的以下解决方案,并且我非常确信它将与实现了 delete
方法的任何其他存储管理器一起工作。(delete
方法是 storage
抽象方法之一,它应该从存储中物理删除文件!)
覆盖模型的 delete
方法,让实例在删除自身之前先删除其 FileFields:
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, using=None, keep_parents=False):
self.song.storage.delete(self.song.name)
self.image.storage.delete(self.image.name)
super().delete()
这对我来说很容易。
如果您想在删除文件之前检查文件是否存在,您可以使用storage.exists
。例如,self.song.storage.exists(self.song.name)
将返回一个代表歌曲是否存在的boolean
。所以它看起来像这样:
def delete(self, using=None, keep_parents=False):
storage = self.song.storage
if storage.exists(self.song.name):
storage.delete(self.song.name)
if storage.exists(self.image.name):
storage.delete(self.image.name)
super().delete()
编辑(附加):
正如@HeyMan所提到的,使用此解决方案调用Song.objects.all().delete()
不会删除文件!这是因为Song.objects.all().delete()
正在运行默认管理器的删除查询。因此,如果想要能够通过使用objects
方法删除模型中的文件,则必须编写和使用自定义管理器(仅用于覆盖其删除查询):
class CustomManager(models.Manager):
def delete(self):
for obj in self.get_queryset():
obj.delete()
为将CustomManager
分配给模型,您必须在模型内部初始化objects
:
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)
objects = CustomManager()
def delete(self, using=None, keep_parents=False):
self.song.storage.delete(self.song.name)
self.image.storage.delete(self.image.name)
super().delete()
现在你可以在任何objects
子查询的末尾使用.delete()
。我编写了最简单的CustomManager
,但你可以通过返回有关已删除对象或其它你想要的信息来更好地完成。