In this blog post we will see how to use AWS S3 to store and serve private media files in django. S3 provides a layer of security by making object private and accessible to those with the valid presigned url and is only valid for however long owner decides.

We will continue from our last blog post on How To Store Django Static and Media Files in AWS S3. In this post we will only discuss parts which involves setting up private media.

Storage Backend

Like we had MediaStorage for user uploaded public media files, we will need to create a new storage backend class for Private media files.

In your_project/custom_storage.py

1
2
3
4
5
class PrivateMediaStorage(S3Boto3Storage):
    location = "private"
    default_acl = "private"
    file_overwrite = False
    custom_domain = False

location: This is the directory in the s3 bucket where all the private files will go. You can change the name as per your need.

default_acl: ACL stands for Access Control List, this enables us to manage access to bucket and objects. Here we are passing private as we want the objects to be private.

file_overwrite: We do not want files to be over-written if they have the same name.

custom_domain: Earlier we’ve set AWS_S3_CUSTOM_DOMAIN in our settings for static and media url generation, however here we want to generate a signed url so we need to set custom domain to False.

Model

It is better to explicitly define the private media storage class in model fields so that we do not unnecessarily complicate other file fields which uses public MediaStorage.

Therefore we need to explicitly pass the PrivateMediaStorage to the model field to store it as private media and generate signed url when we serve.

In your_project/your_app/models.py

1
2
3
4
5
6
class PrivateFile(models.Model):
    file = models.FileField(storage=PrivateMediaStorage(), upload_to="files")
    uploaded_on = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return str(self.uploaded_on.date())

file: This is the field which we are using to point to our private media. You can see we are passing our custom storage class to models.FileField which will now store all our uploads with the settings that we defined for PrivateMediaStorage class.

Conclusion

You can use the file field as you usually do, now all the uploaded files will be private. While calling field you will get a presigned url which will allow users to access the file.

Things to keep in mind

FileField and ImageField in django only stores the location of the file and is created as varchar in database which has max_length of 100. So, if your file location is long then you may want to increase it’s allowed length by passing value to max_length.

FileField

The presigned url is only valid for 1 hour by default, you can change this by setting a different value for querystring_expire (in seconds) in PrivateMediaStorage class.