当我从数据库/模型中删除对象时,如何让Django Admin删除文件?

nar*_*eso 84 django storage file django-models imagefield

我使用1.2.5标准ImageField并使用内置存储后端.文件上传很好但是当我从管理员删除条目时,服务器上的实际文件不会删除.

dar*_*inm 97

您可以接收pre_delete或发post_delete信号(请参阅下面的@ toto_tico注释)并在FileField对象上调用delete方法,因此(在models.py中):

class MyModel(models.Model):
    file = models.FileField()
    ...

# Receive the pre_delete signal and delete the file associated with the model instance.
from django.db.models.signals import pre_delete
from django.dispatch.dispatcher import receiver

@receiver(pre_delete, sender=MyModel)
def mymodel_delete(sender, instance, **kwargs):
    # Pass false so FileField doesn't save the model.
    instance.file.delete(False)
Run Code Online (Sandbox Code Playgroud)

  • 谢谢.一般来说,我建议使用`post_delete`信号,因为如果删除因任何原因失败,它会更安全.然后既不是模型,也不会删除文件,保持数据一致.如果我对`post_delete`和`pre_delete`信号的理解是错误的,请纠正我. (44认同)
  • 确保添加一个检查`instance.file`字段是否为空,或者它(至少可以尝试)删除整个MEDIA_ROOT目录.这甚至适用于`ImageField(null = False)`字段. (10认同)
  • 请注意,如果替换模型实例上的文件,则不会删除旧文件 (8认同)
  • 这在Django 1.8外部管理员中对我不起作用.有新的方法吗? (3认同)

un1*_*n1t 44

尝试django-cleanup

pip install django-cleanup
Run Code Online (Sandbox Code Playgroud)

settings.py

INSTALLED_APPS = (
    ...
    'django_cleanup', # should go after your apps
)
Run Code Online (Sandbox Code Playgroud)

  • 经过有限的测试,我可以确认这个软件包仍适用于Django 1.10. (3认同)

Kus*_*hal 34

Django 1.5解决方案:我使用post_delete的原因是我的应用程序内部的各种原因.

from django.db.models.signals import post_delete
from django.dispatch import receiver

@receiver(post_delete, sender=Photo)
def photo_post_delete_handler(sender, **kwargs):
    photo = kwargs['instance']
    storage, path = photo.original_image.storage, photo.original_image.path
    storage.delete(path)
Run Code Online (Sandbox Code Playgroud)

我把它放在models.py文件的底部.

original_image领域是ImageField我的Photo模型.

  • 对于使用Amazon S3作为存储后端(通过django-storages)的任何人来说,这个特定的答案是行不通的.你会得到一个'NotImplementedError:这个后端不支持绝对路径.你可以通过将文件字段的名称传递给`storage.delete()`而不是文件字段的路径来轻松解决这个问题.例如,用`storage,name = photo.original_image.storage,photo.original_image.name`然后`storage.delete(name)`替换这个答案的最后两行. (5认同)
  • @Sean +1,我在1.7中使用该调整来删除django-storagekit在S3上通过django-storages生成的缩略图.https://docs.djangoproject.com/en/dev/ref/files/storage/#the-storage-class.注意:如果您只是使用ImageField(或FileField),则可以使用`mymodel.myimagefield.delete(save = False)`.https://docs.djangoproject.com/en/dev/ref/files/file/#additional-methods-on-files-attached-to-objects (2认同)

Dav*_*lli 17

此代码在Django 1.4上运行良好,也可以在Admin面板上运行.

class ImageModel(models.Model):
    image = ImageField(...)

    def delete(self, *args, **kwargs):
        # You have to prepare what you need before delete the model
        storage, path = self.image.storage, self.image.path
        # Delete the model before the file
        super(ImageModel, self).delete(*args, **kwargs)
        # Delete the file after the model
        storage.delete(path)
Run Code Online (Sandbox Code Playgroud)

在删除模型之前获取存储和路径很重要,否则后者在删除时也会保持无效.

  • 这个解决方案错了!删除行时不总是调用`delete`,必须使用信号. (4认同)
  • 这对我来说不起作用(Django 1.5)和Django 1.3 CHANGELOG声明:"在Django 1.3中,当删除模型时,不会调用FileField的delete()方法.如果你需要清除孤立文件,你就是'我需要自己处理它(例如,使用可以手动运行或计划通过例如cron定期运行的自定义管理命令)." (3认同)

un3*_*33k 9

需要删除同时在实际的文件deleteupdate.

from django.db import models

class MyImageModel(models.Model):
    image = models.ImageField(upload_to='images')

    def remove_on_image_update(self):
        try:
            # is the object in the database yet?
            obj = MyImageModel.objects.get(id=self.id)
        except MyImageModel.DoesNotExist:
            # object is not in db, nothing to worry about
            return
        # is the save due to an update of the actual image file?
        if obj.image and self.image and obj.image != self.image:
            # delete the old image file from the storage in favor of the new file
            obj.image.delete()

    def delete(self, *args, **kwargs):
        # object is being removed from db, remove the file from storage first
        self.image.delete()
        return super(MyImageModel, self).delete(*args, **kwargs)

    def save(self, *args, **kwargs):
        # object is possibly being updated, if so, clean up.
        self.remove_on_image_update()
        return super(MyImageModel, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)


Sys*_*dox 6

您可以考虑使用pre_delete或post_delete信号:

https://docs.djangoproject.com/en/dev/topics/signals/

当然,删除FileField自动删除的相同原因也适用于此处.如果删除在其他地方引用的文件,则会出现问题.

在我的情况下,这似乎是合适的,因为我有一个专用的文件模型来管理我的所有文件.

注意:由于某种原因,post_delete似乎无法正常工作.该文件被删除,但数据库记录仍然存在,这与我的预期完全相反,即使在错误条件下也是如此.pre_delete工作得很好.

  • 可能`post_delete`将不起作用,因为`file_field.delete()`默认将模型保存到db,尝试`file_field.delete(False)`https://docs.djangoproject.com/en/1.3/ref/models /fields/#django.db.models.FieldFile.delete (3认同)