Django 2.x 解决方案:
在 Django 2 中处理文件删除非常容易。我尝试过使用 Django 2 和 SFTP Storage 以及 FTP STORAGE 的以下解决方案,我很确定它可以与任何其他实现 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):
# assuming that you use same storage for all files in this model:
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() 正在运行Default Manager 的删除查询。因此,如果您希望能够使用objects 方法删除模型的文件,则必须编写并使用Custom Manager(仅用于覆盖其删除查询):
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() # just add this line of code inside of your model
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,但你可以通过返回一些关于你删除的对象或任何你想要的东西来做得更好。