Search code examples
djangoamazon-s3django-storage

Django-Storages change s3 bucket on existing object


I have a django app that allows files to be uploaded to an S3 bucket using django-storages. The file is for a part that needs to be approved. Once it is approved, I'd like to move the file to a different S3 bucket.

class DesignData(models.Model):
    file = models.FileField(storage=PublicMediaStorage())
    ...
class PublicMediaStorage(S3Boto3Storage):
    location = "media"
    default_acl = "public-read"
    file_overwrite = False

After approval, I copy the file over to the new bucket using:

        client.copy_object(
            Bucket=settings.AWS_APPROVED_STORAGE_BUCKET_NAME,
            CopySource=copy_source,
            Key=design_data["s3key"],
        )

The file gets moved correctly however I need to update my object. How can I update the object? Trying something like myObject.file = "newbucket/myfile.txt" won't work as it is expecting an actual file. I've read I should be able to update the url with myObject.file.url = "newbucketaddress/myfile.txt" but I get an error AttributeError: can't set attribute.

Is there a way in django-storages with s3 to update an existing file s3 bucket?


Solution

  • I ended up using somewhat of a workaround to resolve my issue. I ended up changing my model to include another file which would then store the new s3 bucket location.

    class DesignData(models.Model):
        file = models.FileField(storage=PublicMediaStorage())
        approved_file = models.FileField(storage=ApprovedPublicMediaStorage())
    

    I added ApprovedPublicMediaStorage():

    class PublicMediaStorage(S3Boto3Storage):
        location = "media"
        default_acl = "public-read"
        file_overwrite = False
        custom_domain = "newbucketlocation0.s3...."
    

    I did learn the hard way so make sure to include the custom_domain otherwise it will use the default_storage in the settings if it has been assigned. After I copy the file over to the new storage, I delete the old file and change file = null so only approved_file contains an s3 object.