Django 存储 AWS S3:从模型记录中删除文件

20

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

现在我正在尝试找到一种方法,删除包含 S3 文件的模型中的行。我能够使用 .delete() 删除行,但它不会在 S3 中删除。

如何使删除行也在 S3 中删除?

以下是我的代码:

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

@api_view(['POST'])
def delete_employee(request):
    # ----- YAML below for Swagger -----
    """
    description: This API deletes employee
    parameters:
      - name: employee_id
        type: integer
        required: true
        location: form
    """
    employee_id = request.POST['employee_id']
    employee = Employee.objects.get(id = employee_id)
    logging.debug(f"API employee username {employee.username}")
    employee.delete() <---------- here is where the delete row happens
    return Response("Employee Deleted!", status=status.HTTP_200_OK)

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

class Employee(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee')
    company = models.ForeignKey(Company)
    username = models.CharField(max_length=30, blank=False)
    upload = models.FileField(blank=True) <--- S3 field

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

AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = config('AWS_STORAGE_BUCKET_NAME')
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}

DEFAULT_FILE_STORAGE = 'railercomapp.storage_backends.MediaStorage'

https://gitlab.com/firdausmah/railercom/blob/master/railercomapp/storage_backends.py from storages.backends.s3boto3 import S3Boto3Storage

class MediaStorage(S3Boto3Storage):
    location = 'media/yy'
    file_overwrite = False
3个回答

36

您必须明确地删除该文件。您可以编写后删除信号或在delete_employee函数中执行。

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

关于FileField.delete()的文档有详细的解释。

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

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


7
谢谢,你刚刚拯救了我的编程生涯。 - Shubham Gupta

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接