Search code examples
djangoamazon-s3botodjango-storage

Saving another file with same name using django-storage and boto


I have a model Profile and an ImageField associated with it.

The images are uploaded to AWS S3 bucket for storage using django-storages and boto.

If I upload an image with a file name that already exists(eg: sample.png) Django by default would save the new file as sample_1.png which is not working while uploading an image to AWS S3. Is there a way to solve this issue?

How do I upload an image with an already existing file name to AWS S3 without overwriting it?


Solution

  • Given you've defined your bucket location in settings.MYMODEL_FILES_LOCATION you can use the following to rename the uploaded files in an arbitrary location, possible derived from the original file name. Following snippet would save the files in /mymodelfiles/.. The model instance properties can be accessed from the instance object in the renaming method, so you can e.g. upload files from the same user under the same subdirectory.

    import uuid
    import os
    from django.utils.deconstruct import deconstructible
    from storages.backends.s3boto import S3BotoStorage
    from django.db import models
    from django.conf import settings
    
    
    def path_and_rename(prefix, filename):
        ext = filename.split('.')[-1]
        filename = '{}.{}'.format(uuid.uuid4().hex, ext)
        return os.path.join(prefix, filename)
    
    
    def get_path_for_my_model_file(instance, filename):
        return path_and_rename('mymodelfiles/', filename)
    
    
    @deconstructible
    class MyS3BotoStorage(S3BotoStorage):
        pass
    
    
    class MyModel(models.Model):
        resources = models.FileField(
            upload_to=get_path_for_my_model_file,
            storage=MyS3BotoStorage(bucket=settings.MYMODEL_FILES_LOCATION))
    

    Constructor of S3BotoStorage can take keyword argument "acl" to set permissions for the uploaded file, e.g. acl='private'