我正在用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()它会从数据库中删除记录,但不会删除服务器上的文件。我还能尝试什么呢?
谢谢!
发布于 2013-04-16 23:50:57
在Django 1.3之前,当您删除相应的模型实例时,文件会自动从文件系统中删除。您可能正在使用较新的Django版本,因此您必须自己实现从文件系统中删除文件。
基于信号的简单样本
我在撰写本文时选择的方法是post_delete和pre_save信号的混合,这使得每当删除相应的模型或更改其文件时,过时的文件都会被删除。
基于一个假设的MediaFile模型:
import os
import 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()方法调用恰好在一个被回滚的事务中,你的数据最终可能会引用一个不存在的文件。您可以考虑将文件删除逻辑包装到transaction.on_commit()中,就像transaction.on_commit(lambda: os.remove(old_file.path))、as suggested in Mikhail’s comment一样。django-cleanup库does something along those lines.
save() (例如,通过批量更新QuerySet),则旧文件将继续存在,因为信号将不会运行。如果您使用传统的文件处理methods.
file作为字段名,这不是一个好的样式,因为它与内置的file对象标识符冲突。附录:定期清理
实际上,您可能还希望运行一个定期任务来处理孤立文件清理,以防运行时故障导致某些文件无法删除。考虑到这一点,您可能会完全摆脱信号处理程序,并使这样的任务成为处理不敏感数据和不太大的文件的机制。
但是,无论哪种方式,如果您正在处理敏感数据,最好是反复检查,确保您始终及时删除生产中的数据,以避免任何相关的责任。
另请参阅
Django 1.11模型字段引用中的
FieldFile.delete() (请注意,它描述了FieldFile类,但您可以直接在字段上调用.delete():FileField实例代理到相应的FieldFile实例,并且您可以像访问字段的方法一样访问它的方法)请注意,删除模型时,不会删除相关文件。如果您需要清理孤立文件,则需要自己处理(例如,使用可以手动运行或计划通过cron定期运行的自定义管理命令)。
在早期的Django版本中,当包含FileField的模型实例被删除时,FileField自己也会从后端存储中删除该文件。这打开了几种数据丢失场景的大门,包括回滚事务和引用同一文件的不同模型上的字段。在Django1.3中,当一个模型被删除时,FileField的delete()方法不会被调用。如果您需要清理孤立文件,则需要自己处理(例如,使用可以手动运行或计划通过cron定期运行的自定义管理命令)。
发布于 2015-03-11 20:14:47
试试django-cleanup,当你移除模型时,它会自动调用FileField上的delete方法。
pip install django-cleanupsettings.py
INSTALLED_APPS = (
...
'django_cleanup.apps.CleanupConfig',
)发布于 2017-02-03 16:37:49
在Django >= 1.10中,可以通过调用文件字段的.delete方法从文件系统中删除文件,如下图所示:
obj = Song.objects.get(pk=1)
obj.song.delete()https://stackoverflow.com/questions/16041232
复制相似问题