当删除数据库中的一行时,如何从S3中同时删除相应的文件? (姜戈)

问题描述 投票:0回答:3

我的 Django AWS S3 解决方案基于 https://simpleisbetterthancomplex.com/tutorial/2017/08/01/how-to-setup-amazon-s3-in-a-django-project.html.

现在我正在尝试找到一种方法来删除模型中包含 S3 文件的行。我可以使用

.delete()
删除该行,但它不会删除 S3 中相应的文件。

如何使删除该行的同时删除S3中对应的文件?我正在使用 Django 和 django-storages

下面是我的代码:(有关更多详细信息,请参阅编辑历史记录):

https://gitlab.com/firdausmah/railercom/blob/master/railercomapp/api.py

https://gitlab.com/firdausmah/railercom/blob/master/railercomapp/models.py

https://gitlab.com/firdausmah/railercom/blob/master/railercom/settings.py(AWS 设置)

https://gitlab.com/firdausmah/railercom/blob/master/railercomapp/storage_backends.py

django amazon-web-services amazon-s3 delete-row django-storage
3个回答
39
投票

您必须明确删除该文件。您可以编写一个post删除信号或在

delete_employee
函数中执行此操作。

employee.upload.delete(save=False)  # delete file
employee.delete()  # delete model instance

FileField.delete()
的文档解释了这一点。

请注意,删除模型时,相关文件不会被删除。如果您需要清理孤立文件,则需要自己处理(例如,使用可以手动运行或通过 cron 等安排定期运行的自定义管理命令)。

在删除该文件之前,您还应该确保没有其他 FileField 引用完全相同的文件。


2
投票

对于我所有努力删除带有 django-storages 的文件夹的兄弟。

让我们考虑一个真实的案例。我有一个动态路径,每个文件都存储在文件夹中,我必须实施清理。

def get_upload_path(instance, filename):
    return os.path.join(
        'organizations',
        'files',
        str(instance.organization.pk),
        str(instance.hash),
        str(filename)
    )

file = models.FileField(
    upload_to=get_upload_path
)

我的案例的问题是在清理过程中我无法删除带有 django-storages 的文件夹。

instance.file.name
会引发错误,因为您无法使用 django-storages 获得文件的绝对路径。 要删除文件夹,您应该使用
storage.delete()
,因为您无法拥有绝对路径,因此无法以直接的方式删除文件夹(例如
shutil.rmtree(...)
)。

我的清理实现有点复杂,但很可靠。就我而言,我使用了 pre_delete 信号并建议您也这样做。


from django.core.files.storage import get_storage_class

default_storage = get_storage_class()()

@receiver(pre_delete, sender=OrganizationFile)
def delete_has_folder(sender, instance, *args, **kwargs):
    # get filename that will be equals to the relative path but not actually the filename
    path = Path(instance.file.name)
    # get a parent folder str
    folder_path = str(path.parent)
    
    # delete a file
    instance.file.delete()
    # delete a folder. 
    #  shutil.rmtree(absolute_path) wouldn't work
    #  because instance.file.path will raise an error.
    #  hence the only way is to delete with a storage default_storage.delete
    default_storage.delete(folder_path)

    logger.info(f'Pre delete {instance}. Deleted the hash folder {folder_path}')


0
投票

我用的是这个:

import boto3

client = boto3.client('s3')
client.delete_object(Bucket='mybucketname', Key='myfile.whatever')

但是我正在尝试找到一种方法来使用我的模型的 ImageFile 对象,或者可能使用我的存储类的某些配置来实现此目的:

from storages.backends.s3boto3 import S3Boto3Storage 

class MediaStorage(S3Boto3Storage):    
    location = 'media'    
    file_overwrite = True
© www.soinside.com 2019 - 2024. All rights reserved.