我正在 Django 中构建一个网络应用程序。我有一个上传文件的模型,但无法删除该文件。这是我的代码:
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()
它从数据库中删除记录,但不删除服务器上的文件。
我还能尝试什么?
Thanks!
在 Django 1.3 之前,当您删除相应的模型实例时,该文件会自动从文件系统中删除。您可能使用的是较新的 Django 版本,因此您必须自己从文件系统中删除该文件。
简单的基于信号的示例
我在撰写本文时选择的方法是混合使用post_delete
and pre_save
信号,这样每当删除相应模型或更改其文件时,就会删除过时的文件。
基于一个假设MediaFile
model:
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))
, 正如米哈伊尔评论中所建议的. django-cleanup
图书馆沿着这些思路做一些事情.
- 边缘情况:如果您的应用程序上传新文件并将模型实例指向新文件而不调用
save()
(例如通过批量更新QuerySet
),旧文件将继续存在,因为信号不会运行。如果您使用传统的文件处理方法,则不会发生这种情况。
- 编码风格:本例使用
file
作为字段名称,这不是一个好的样式,因为它与内置的冲突file
对象标识符。
附录:定期清理
实际上,您可能想要also运行定期任务来处理孤立文件清理,以防运行时故障导致某些文件无法被删除。考虑到这一点,您可能可以完全摆脱信号处理程序,并执行这样的任务the处理不敏感数据和不太大文件的机制。
不管怎样,如果你are处理敏感数据时,最好仔细检查一下,确保及时删除生产中的数据,以避免承担任何相关责任。
See also
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)