Django storages + boto3 not working. Keeping static files local while uploading media files to S3

I'm trying to setup a django project in such a way that static files are kept in the filesystem and media files are uploaded to an amazon s3 bucket. The django storages library had an update for django>4.2. This used to be easy, now, its not working with the new settings:

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_STORAGE = 'django.core.files.storage.FileSystemStorage'

# Check if running in a production environment
STORAGES = {
    'default': {
        'BACKEND': 'storages.backends.s3boto3.S3Boto3Storage',
        'OPTIONS': {
            'bucket_name': os.getenv('AWS_STORAGE_BUCKET_NAME'),
            'region_name': os.getenv('AWS_S3_REGION_NAME', 'us-east-1'),
            'default_acl': 'public-read',
            'file_overwrite': False,
            'custom_domain': f'{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.{os.getenv("AWS_S3_REGION_NAME", "us-east-1")}.amazonaws.com',
        },
    },
    'staticfiles': {
        'BACKEND': 'django.core.files.storage.FileSystemStorage',
        'OPTIONS': {
            'location': STATIC_ROOT,
        },
    }
}
# django-storages configuration for media files
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = f'https://{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.{os.getenv("AWS_S3_REGION_NAME", "us-east-1")}.amazonaws.com/media/'

When accessing the site from the server, the static files still point to the s3 bucket, for example:

us-east-1.amazonaws.com/media/admin/css/dark_mode.css

That is the basic css for the django admin. But why is it looking for the file in /media/?

I think you can get rid of Boto3 and use default storages.backends.s3.S3Storage backend, also you have to pass AWS keys either via options or environment variables. See below working code, but in my case storing both static and media files in Yandex S3.

ENDPOINT = 'storage.yandexcloud.net'
ENDPOINT_URL = 'https://' + ENDPOINT

STATIC_URL = f"{ENDPOINT_URL}/{env.str("BUCKET_NAME")}/static/"
MEDIA_URL = f"{ENDPOINT_URL}/{env.str("BUCKET_NAME")}/media/"

default_storage_backend = "storages.backends.s3.S3Storage"
default_storage_options = {
    "access_key": env.str("YOS_ACCESS_KEY"),
    "secret_key": env.str("YOS_SECRET_KEY"),
    "bucket_name": env.str("BUCKET_NAME"),
    "region_name": env.str("BUCKET_REGION"),
    "endpoint_url": ENDPOINT_URL,
    "custom_domain": f"{ENDPOINT}/{env.str('BUCKET_NAME')}",
    "default_acl": 'public-read',
    "querystring_auth": False,
    "file_overwrite": True,
}
STORAGES = {
    "staticfiles": {
        "BACKEND": default_storage_backend,
        "OPTIONS": {
            **default_storage_options,
            "location": "static",
        } 
    },
    "default": {
        "BACKEND": default_storage_backend,
        "OPTIONS": {
            # add or override options defined in default
            **default_storage_options,
            "location": "media",
        },
    },
}

and environment:

YOS_ACCESS_KEY='...'
YOS_SECRET_KEY='...'
BUCKET_NAME=...
BUCKET_REGION=... 

For AWS it should be:

"custom_domain": f"{env.str(BUCKET_NAME)}.{ENDPOINT}",

and

ENDPOINT = 's3.amazonaws.com'
ENDPOINT_URL = f"https://{env.str(BUCKET_NAME)}.{ENDPOINT}"
...
STATIC_URL = f"{ENDPOINT_URL}/static/"
MEDIA_URL = f"{ENDPOINT_URL}/media/"

I think you could leave your static as it is and change only default storage for media files.

I used https://forum.djangoproject.com/t/storage-4-2-how-to-subclass-default/29190/3 and official docs are here https://django-storages.readthedocs.io/en/stable/backends/amazon-S3.html

Back to Top