Storage & backups

Django

2 min read

django-storages lets Django store uploaded files (FileField, ImageField) and static files in object storage. The examples are for Django 4.2 or later.

Installation

pip install "django-storages[s3]>=1.14" "boto3>=1.36"

Configuration

Pass the keys through environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) and add the storage settings to settings.py. In this example, user files are private, and static files are in the static/ folder with public access:

from botocore.config import Config

S3_OPTIONS = {
    "bucket_name": "my-bucket",
    "endpoint_url": "https://s3.uzcstorage.uz",
    "region_name": "default",
    "client_config": Config(
        signature_version="s3v4",
        s3={"addressing_style": "path"},
        request_checksum_calculation="when_required",
        response_checksum_validation="when_required",
    ),
}

STORAGES = {
    # Uploaded files: private, accessed by temporary links
    "default": {
        "BACKEND": "storages.backends.s3.S3Storage",
        "OPTIONS": {
            **S3_OPTIONS,
            "location": "media",
            "default_acl": None,
            "querystring_auth": True,
            "querystring_expire": 3600,
            "file_overwrite": False,
        },
    },
    # Static files: public, permanent links
    "staticfiles": {
        "BACKEND": "storages.backends.s3.S3Storage",
        "OPTIONS": {
            **S3_OPTIONS,
            "location": "static",
            "default_acl": None,
            "querystring_auth": False,
            "custom_domain": "s3.uzcstorage.uz/my-bucket",
        },
    },
}

Open read access to the static/ folder with a bucket policy (replace public/* with static/* in the example), then upload the static files:

python manage.py collectstatic --noinput

Models and Files

Model fields work as usual — the files are saved to the bucket:

from django.db import models

class Document(models.Model):
    title = models.CharField(max_length=200)
    file = models.FileField(upload_to="documents/%Y/%m/")

# In a view:
doc = Document.objects.create(title="Report", file=request.FILES["file"])
doc.file.url   # temporary link, valid for querystring_expire seconds

Working with storage directly:

from django.core.files.base import ContentFile
from django.core.files.storage import default_storage

path = default_storage.save("exports/report.csv", ContentFile(b"id,name\n1,Demo\n"))
default_storage.exists(path)
with default_storage.open(path) as f:
    data = f.read()
default_storage.delete(path)

Several Storages

To keep some files in a separate bucket (for example, public images), create a storage class and pass it to the field:

from storages.backends.s3 import S3Storage

class PublicMediaStorage(S3Storage):
    bucket_name = "my-public-bucket"
    querystring_auth = False
    custom_domain = "s3.uzcstorage.uz/my-public-bucket"

class Product(models.Model):
    image = models.ImageField(upload_to="products/", storage=PublicMediaStorage())

Connection settings (endpoint_url, region_name, client_config) for such a class are taken from the AWS_S3_ENDPOINT_URL, AWS_S3_REGION_NAME and AWS_S3_CLIENT_CONFIG variables in settings.py.

Tip

For direct work with S3 in Python code (multipart uploads, presigned upload links), see Python (boto3).

Tip

See also: