在Django 1.3之前,当您删除相应的模型实例时,文件会自动从文件系统中删除.您可能正在使用较新的Django版本,因此您必须自己实现从文件系统中删除文件.
基于简单信号的采样
我在 compose 本文时 Select 的方法是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)
- 我想我不久前开发的其中一个应用程序在生产中使用了此代码,但使用风险自负.
- 例如,有一个possible data loss场景:如果
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
),则旧文件将继续存在,因为信号将不会运行.如果您使用传统的文件处理方法,则不会发生这种情况.
- 编码样式:本例使用
file
作为字段名,这不是一个好的样式,因为它与内置的file
对象标识符冲突.
附录:定期清理
实际上,您可能希望also运行一个定期任务来处理孤立文件清理,以防运行时故障导致某些文件无法删除.考虑到这一点,您可能完全摆脱了信号处理程序,并建立了这样一种任务the机制来处理不敏感的数据和不太大的文件.
不管怎样,如果你在处理敏感数据,最好是反复判断,确保在生产过程中永远不会不及时删除数据,以避免任何相关责任.
另见
Django 1.11模型字段参考中的FieldFile.delete()
(请注意,它描述了FieldFile
类,但您可以直接在字段上调用.delete()
:FileField
个实例代理对应的FieldFile
实例,您可以像访问字段的方法一样访问它的方法)
请注意,删除模型时,不会删除相关文件.如果您需要清理孤立文件,则需要自己处理(例如,使用可以手动运行或计划通过cron定期运行的自定义管理命令).
Django不自动删除文件的原因:entry in release notes for Django 1.3
在早期的Django版本中,当一个包含FileField
的模型实例被删除时,FileField
会自行从后端存储中删除该文件.这为几种数据丢失场景打开了大门,包括引用同一文件的不同模型上的回滚事务和字段.在Django 1.3中,当模型被删除时,将不会调用FileField
的delete()
方法.如果需要清理孤立文件,则需要自己处理(例如,使用自定义管理命令,该命令可以手动运行,也可以通过cron定期运行).
Example of using a pre_delete
signal only个