Django删除FileField
我正在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()
它从数据库中删除,但不删除服务器上的文件。我还能尝试什么?
回答:
在Django 1.3之前,当你删除相应的模型实例时,文件会自动从文件系统中删除。你可能正在使用较新的Django版本,因此你必须自己实现从文件系统中删除文件。
你可以通过几种方式做到这一点,其中一种方式是使用pre_delete
或post_delete
信号。
例
我目前选择的方法是post_delete
和pre_save
信号的混合,这样可以确保在删除相应的模型或更改其文件时删除过时的文件。
基于一个假设MediaFile
模型:
import osimport uuid
from django.db import models
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
class MediaFile(models.Model):
file = models.FileField(_("file"),
upload_to=lambda instance, filename: str(uuid.uuid4()))
# These two auto-delete files from filesystem when they are unneeded:
@receiver(models.signals.post_delete, sender=MediaFile)
def auto_delete_file_on_delete(sender, instance, **kwargs):
"""
Deletes file from filesystem
when corresponding `MediaFile` object is deleted.
"""
if instance.file:
if os.path.isfile(instance.file.path):
os.remove(instance.file.path)
@receiver(models.signals.pre_save, sender=MediaFile)
def auto_delete_file_on_change(sender, instance, **kwargs):
"""
Deletes old file from filesystem
when corresponding `MediaFile` object is updated
with new file.
"""
if not instance.pk:
return False
try:
old_file = MediaFile.objects.get(pk=instance.pk).file
except MediaFile.DoesNotExist:
return False
new_file = instance.file
if not old_file == new_file:
if os.path.isfile(old_file.path):
os.remove(old_file.path)
- 极端情况:如果你的应用程序上传了一个新文件并在未调用的情况下将模型实例指向该新文件
save()
(例如,通过批量更新QuerySet),则旧文件将继续散布,因为不会运行信号。如果使用常规文件处理方法,则不会发生这种情况。 - 我认为我构建的其中一个应用程序已在生产中使用此代码,但使用时后果自负。
编码样式:此示例将其file用作字段名称,但这不是一个好的样式,因为它与内置file对象标识符冲突。
也可以看看
FieldFile.delete()
在Django 1.11模型字段参考中(请注意,它描述了FieldFile
该类,但你将.delete()
直接在该字段上调用:FileField
实例代理对应的FieldFile实例,并且可以像访问字段的方法一样访问其方法)
请注意,删除模型时,不会删除相关文件。如果需要清理孤立的文件,则需要自己处理(例如,使用可手动运行或计划通过cron定期运行的自定义管理命令)。
- 为什么Django无法自动删除文件:Django 1.3发行说明中的条目
在早期的Django版本中,当FileField删除包含的模型实例时,FileField它会自己从后端存储中删除文件。这为多种数据丢失情况打开了大门,包括回滚的事务和引用同一文件的不同模型上的字段。在Django 1.3中,删除模型后,不会调用FileField的delete()方法。如果需要清除孤立的文件,则需要自己处理(例如,使用可手动运行或计划通过cron定期运行的自定义管理命令)。
- pre_delete仅使用信号的示例
以上是 Django删除FileField 的全部内容, 来源链接: utcz.com/qa/433407.html