Search code examples
pythondjangodigital-oceandigital-ocean-spaces

Django does not seem to work with DigitalOcean Spaces


I have followed multiple tutorials on how to use the DigitalOcean object storage known as DigitalOcean Spaces on my Django project but I'm not able to do it. Actually, I was using it before and it was working, after that I moved the static files to Contabo Object Storage, and apparently their CDN is pretty slow so when I decided to go back to DO, it does not work anymore, I even went to the commit where I had it working and copied the exact same code.

Here is the code I have on my settings.py:

from storages.backends.s3boto3 import S3Boto3Storage


class MediaStorage(S3Boto3Storage):
    bucket_name = "XXXX"


class StaticStorage(S3Boto3Storage):
    bucket_name = "XXXX"


DEFAULT_FILE_STORAGE = "nafssi.settings.MediaStorage"
STATICFILES_STORAGE = "nafssi.settings.StaticStorage"

AWS_ACCESS_KEY_ID = "XXXX"
AWS_SECRET_ACCESS_KEY = "XXX/XXXX/XXXXX"
AWS_S3_ENDPOINT_URL = "https://XXXX.fra1.digitaloceanspaces.com"
AWS_S3_OBJECT_PARAMETERS = {
    "CacheControl": "max-age=86400",
}

MEDIA_URL = f"{AWS_S3_ENDPOINT_URL}/media/"
STATIC_URL = f"{AWS_S3_ENDPOINT_URL}/static/"

When I try python manage.py collectstatic I have the following error:

You have requested to collect static files at the destination
location as specified in your settings.

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: yes
Traceback (most recent call last):
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\manage.py", line 22, in <module>
    main()
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\core\management\__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\core\management\__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\core\management\base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\core\management\base.py", line 458, in execute
    output = self.handle(*args, **options)
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 209, in handle
    collected = self.collect()
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 135, in collect
    handler(path, prefixed_path, storage)
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 368, in copy_file
    if not self.delete_file(path, prefixed_path, source_storage):
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 278, in delete_file
    if self.storage.exists(prefixed_path):
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\storages\backends\s3boto3.py", line 463, in exists
    self.connection.meta.client.head_object(Bucket=self.bucket_name, Key=name)
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\botocore\client.py", line 535, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "D:\Data\Dropbox\D Drive\Toubib\Nafssi\Code\nafssienv\lib\site-packages\botocore\client.py", line 980, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (403) when calling the HeadObject operation: Forbidden

I even added some CORS permissions on DigitalOcean as follows:

enter image description here


Solution

  • I found the solution, by tweaking the configuration, the changes were mainly in the endpoint URL and the media and static urls, also I added the Region Name for it to work.

    Here is the updated code:

    from storages.backends.s3boto3 import S3Boto3Storage
    
    
    class MediaStorage(S3Boto3Storage):
        bucket_name = "XXXX"
    
    
    class StaticStorage(S3Boto3Storage):
        bucket_name = "XXXX"
    
    
    DEFAULT_FILE_STORAGE = "XXXX.settings.MediaStorage"
    STATICFILES_STORAGE = "XXXX.settings.StaticStorage"
    
    AWS_ACCESS_KEY_ID = config("AWS_ACCESS_KEY_ID")
    AWS_SECRET_ACCESS_KEY = config("AWS_SECRET_ACCESS_KEY")
    
    
    AWS_STORAGE_BUCKET_NAME = "XXXX"
    AWS_S3_REGION_NAME = "fra1"
    AWS_S3_ENDPOINT_URL = "https://fra1.digitaloceanspaces.com"
    
    
    AWS_S3_OBJECT_PARAMETERS = {
        "CacheControl": "max-age=86400",
    }
    
    MEDIA_URL = "https://XXXX.fra1.digitaloceanspaces.com/media/"
    STATIC_URL = "https://XXXX.fra1.digitaloceanspaces.com/static/"