The current state of our app is as follows: A client makes a POST request to our Django + DRF app server with one or more files, the django server processes the files, then uploads and saves it to S3. This is done using the amazing django-storages & boto3 libraries. We eventually will have the reference url to our S3 files in our Database.

A very simplified example looks like this:

# models.py

class TestImageModel(models.Model):
    image = models.ImageField(upload_to='<path_in_bucket>', storage=S3BotoStorage())
# serializers.py

class TestImageSerializer(serializers.ModelSerializer):
    image = serializers.ImageField(write_only=True)

The storages library handles uploading to S3 and calling something like:

TestImageModel.objects.first().image.url

will return the reference to the image url in S3 (technically in our case it will be cloudfront URL since we use it as a CDN, and set the custom_domain in S3BotoStorage class)

This was the initial approach we took, but we are noticing heavy server memory usage due to the fact that images are first uploaded to our server, then uploaded again to S3. To scale efficiently, we would like to move to an approach where to instead upload directly from Client to S3 using presigned URLs. I found documentation on how to do so here: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html.

The new strategy I will adopt for image upload:

  1. Client requests Presigned url from Django API
  2. Client uploads to S3 directly
  3. Django updates reference to uploaded image in database with ImageField.

My question is about 3). How can I tell the django record that an already uploaded image in S3 should be the location of the ImageField, without having to reupload the image through S3BotoStorage class?

An alternative could be to change the ImageField to a URLField, and just store the link of the new image, but this will disallow me from using the features of an ImageField (Forms in django admin, deleting directly from S3 using the storage class .delete(), etc).

How can I update the ImageField to point to an existing file in the same storage, or is there a better way to go about moving to a direct Client-S3 upload strategy with Django and ImageField?

1

There are 1 answers

1
Julian Sam On

So apparantly you can just do something like this:

a = TestImageModel.objects.first()
a.image.name = 'path_to_image'
a.save()

And everything works perfectly :)