DigitalOcean Spaces Integration
Overview
DigitalOcean Spaces is S3-compatible object storage that integrates seamlessly with Django applications using django-storages and boto3.
Django Configuration
Required Packages
Add to requirements.txt:
Django Settings
# settings.py
import os
# DigitalOcean Spaces Configuration
USE_SPACES = os.getenv('USE_SPACES') == 'TRUE'
if USE_SPACES:
# AWS S3 settings (DigitalOcean Spaces is S3-compatible)
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
AWS_DEFAULT_ACL = 'public-read'
AWS_S3_ENDPOINT_URL = 'https://nyc3.digitaloceanspaces.com' # Change region as needed
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
# Static files configuration
AWS_LOCATION = 'static'
STATIC_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.nyc3.digitaloceanspaces.com/{AWS_LOCATION}/'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
# Media files configuration
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.nyc3.digitaloceanspaces.com/media/'
Django 4.2+ Storage Configuration
For Django 4.2+, use the new STORAGES setting:
STORAGES = {
"default": {
"BACKEND": "storages.backends.s3.S3Storage",
"OPTIONS": {
"access_key": os.getenv('AWS_ACCESS_KEY_ID'),
"secret_key": os.getenv('AWS_SECRET_ACCESS_KEY'),
"bucket_name": os.getenv('AWS_STORAGE_BUCKET_NAME'),
"endpoint_url": "https://nyc3.digitaloceanspaces.com",
"default_acl": "public-read",
"object_parameters": {
"CacheControl": "max-age=86400",
},
},
},
"staticfiles": {
"BACKEND": "storages.backends.s3.S3StaticStorage",
"OPTIONS": {
"access_key": os.getenv('AWS_ACCESS_KEY_ID'),
"secret_key": os.getenv('AWS_SECRET_ACCESS_KEY'),
"bucket_name": os.getenv('AWS_STORAGE_BUCKET_NAME'),
"endpoint_url": "https://nyc3.digitaloceanspaces.com",
"location": "static",
},
},
}
Environment Variables
# .env file
USE_SPACES=TRUE
AWS_ACCESS_KEY_ID=your_spaces_access_key
AWS_SECRET_ACCESS_KEY=your_spaces_secret_key
AWS_STORAGE_BUCKET_NAME=your_bucket_name
Boto3 Direct Usage
Basic Setup
import boto3
import os
# Create session
session = boto3.session.Session()
client = session.client(
's3',
region_name='nyc3',
endpoint_url='https://nyc3.digitaloceanspaces.com',
aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY')
)
File Operations
# Upload file
with open('local_file.txt', 'rb') as file_contents:
client.put_object(
Bucket='your-bucket-name',
Key='uploads/local_file.txt',
Body=file_contents,
ACL='public-read'
)
# Download file
client.download_file(
Bucket='your-bucket-name',
Key='uploads/local_file.txt',
Filename='downloaded_file.txt'
)
# Generate presigned URL
url = client.generate_presigned_url(
ClientMethod='get_object',
Params={'Bucket': 'your-bucket-name', 'Key': 'uploads/local_file.txt'},
ExpiresIn=3600 # 1 hour
)
DigitalOcean CLI (doctl) Integration
Authentication
# Install doctl
sudo snap install doctl
# Create alias
echo "alias doctl='snap run doctl'" >> ~/.bash_aliases
# Authenticate
doctl auth init --context azmx
# Enter your DigitalOcean API token
# Switch contexts
doctl auth switch --context azmx
Spaces Management
# List spaces
doctl compute spaces list
# Create space
doctl compute spaces create my-new-space --region nyc3
# Upload file
doctl compute spaces cp local_file.txt do:my-space/uploads/
# Download file
doctl compute spaces cp do:my-space/uploads/file.txt local_file.txt
CDN Configuration
For CDN-enabled Spaces
# Note: Use the origin endpoint for boto3, not the CDN endpoint
AWS_S3_ENDPOINT_URL = 'https://nyc3.digitaloceanspaces.com' # NOT .cdn.digitaloceanspaces.com
# For presigned URLs with CDN
from botocore.client import Config
client = session.client(
's3',
region_name='nyc3',
endpoint_url='https://nyc3.digitaloceanspaces.com',
aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'),
config=Config(s3={'addressing_style': 'virtual'})
)
File Upload in Django Views
Example View
from django.shortcuts import render
from django.core.files.storage import default_storage
from django.conf import settings
def upload_file(request):
if request.method == 'POST' and request.FILES['file']:
uploaded_file = request.FILES['file']
file_path = default_storage.save(
f'uploads/{uploaded_file.name}',
uploaded_file
)
file_url = default_storage.url(file_path)
return render(request, 'success.html', {'file_url': file_url})
return render(request, 'upload.html')
Common Issues and Solutions
1. Static Files Not Uploading
Ensure STATIC_ROOT is set even when using Spaces:
2. CORS Issues
Configure CORS in DigitalOcean Spaces control panel for web access.
3. ACL Warnings
Django-storages will default to no ACL in version 2.0. Set explicitly:
AWS_DEFAULT_ACL = None # Use bucket's default ACL
# OR
AWS_DEFAULT_ACL = 'public-read' # Make files publicly readable
Performance Optimization
Caching Headers
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400', # 24 hours
'Expires': 'Thu, 31 Dec 2099 20:00:00 GMT',
}
Compression
# Enable gzip compression for text files
AWS_IS_GZIPPED = True
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}