我正在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版本,因此您必须自己实现从文件系统中删除文件.

基于简单信号的采样

我在 compose 本文时 Select 的方法是post_deletepre_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中,当模型被删除时,将不会调用FileFielddelete()方法.如果需要清理孤立文件,则需要自己处理(例如,使用自定义管理命令,该命令可以手动运行,也可以通过cron定期运行).

  • Example of using a pre_delete signal only

Django相关问答推荐

Django Model邮箱字段是必需的,即使在我将其设置为NULL=True和BLACK=True之后也是如此

在模板中自动添加变量

RDBMS多对多关系Django

注册新用户时,对象没有属性';is_active';错误:';NoneType';对象没有属性

执行官/start.sh:没有这样的文件或目录

从多个数据库访问 Django 会话

如何在没有此前缀的情况下修复此 django 路径?

在 Django 模板中分页时如何正确显示与其父模型字段关联的所有内联字段?

Django 如何知道我的数据库的路径?

Django授权判断具有通配符模式的URL

Django:如何在表单 clean() 方法的 django 验证错误中添加 超链接?

模型中的外键

django- nginx: [emerg] open() "/etc/nginx/proxy_params" 在 /etc/nginx/sites-enabled/myproject:11 中失败(2:没有这样的文件或目录)

将 XML 从 URL 解析为 python 对象

Django admin:我可以定义字段顺序吗?

有 Django List View 模型排序吗?

如何将我的上下文变量传递给 Django 中的 javascript 文件?

Django 1.7 - 如何 suppress (1_6.W001)某些元素单元测试可能无法按预期执行.?

django/文件上传权限

Django ModelForm 覆盖小部件