Django storage backend for Supabase buckets
Project description
django-supabase-storage
A Django storage backend for Supabase buckets. Store your media and static files directly in Supabase Storage with a simple, drop-in replacement for Django's default storage backend.
Features
- Direct Supabase Storage Integration: Upload files directly to Supabase buckets
- No Local Storage: All files are stored in Supabase, not locally
- Media & Static Storage: Separate storage backends for media and static files
- Django Compatible: Works as a drop-in replacement for Django's default storage
- Easy Configuration: Simple settings-based configuration
- Production Ready: Comprehensive error handling and logging
Quick Start
1. Installation
pip install django-supabase-storage
2. Configuration
Add to your Django settings:
import os
# Supabase Configuration
SUPABASE_URL = os.getenv('SUPABASE_URL', 'https://your-project-id.supabase.co')
SUPABASE_KEY = os.getenv('SUPABASE_KEY', 'your-anon-public-key')
SUPABASE_BUCKET = os.getenv("SUPABASE_BUCKET_NAME", 'your-supabase-bucket-name')
# Storage Configuration (Django 4.2+)
STORAGES = {
'default': {
'BACKEND': 'django_supabase_storage.SupabaseMediaStorage',
},
'staticfiles': {
'BACKEND': 'django_supabase_storage.SupabaseStaticStorage',
},
}
# For Django < 4.2, use:
# DEFAULT_FILE_STORAGE = 'django_supabase_storage.SupabaseMediaStorage'
# STATICFILES_STORAGE = 'django_supabase_storage.SupabaseStaticStorage'
3. Set Environment Variables
Create a .env file:
SUPABASE_URL=https://your-project-id.supabase.co
SUPABASE_KEY=your-anon-public-key
SUPABASE_BUCKET_NAME=your-supabase-bucket-name
Using Storage Classes
Media Files Storage
For user uploads (images, documents, etc.):
from django.core.files.storage import default_storage
# Save a file to the media bucket
file_path = default_storage.save('uploads/myfile.pdf', file_content)
# Get the public URL
file_url = default_storage.url(file_path)
# Delete a file
default_storage.delete('uploads/myfile.pdf')
# Check if file exists
if default_storage.exists('uploads/myfile.pdf'):
content = default_storage.open('uploads/myfile.pdf').read()
In Django Models:
from django.db import models
class UserProfile(models.Model):
avatar = models.ImageField(upload_to='avatars/')
resume = models.FileField(upload_to='resumes/')
bio = models.TextField()
In Views:
from django.shortcuts import render
from django.core.files.storage import default_storage
def upload_avatar(request):
if request.method == 'POST':
file = request.FILES['avatar']
# Save automatically goes to Supabase
file_path = default_storage.save(f'avatars/{request.user.id}/{file.name}', file)
file_url = default_storage.url(file_path)
return render(request, 'success.html', {'url': file_url})
return render(request, 'upload.html')
Static Files Storage
For CSS, JavaScript, and static images:
from django.templatetags.static import static
# In your Django templates
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<script src="{% static 'js/main.js' %}"></script>
Collecting Static Files:
# Django automatically collects static files to Supabase
python manage.py collectstatic
This uploads all your static files to the 'static' bucket in Supabase.
Storage Backends
SupabaseStorage (Base Class)
The base storage class for custom implementations:
from django_supabase_storage import SupabaseStorage
class CustomStorage(SupabaseStorage):
folder_path = 'custom/' # All files saved under this folder
SupabaseMediaStorage
Handles user-uploaded media files:
- Bucket: 'media' (by default)
- Folder: 'media'
- Use Case: Profile pictures, documents, user uploads
from django_supabase_storage import SupabaseMediaStorage
# Direct usage
storage = SupabaseMediaStorage()
path = storage.save('documents/myfile.pdf', content)
url = storage.url(path)
SupabaseStaticStorage
Handles static application files:
- Bucket: 'static' (by default)
- Folder: 'static'
- Use Case: CSS, JavaScript, application images
from django_supabase_storage import SupabaseStaticStorage
# Used automatically with collectstatic
# Or directly:
storage = SupabaseStaticStorage()
path = storage.save('js/app.js', content)
url = storage.url(path)
Complete Setup Example
Step 1: Create Supabase Buckets
- Go to supabase.com and create a project
- Navigate to Storage → Buckets
- Create bucket named
media - Create bucket named
static - For each bucket, go to Policies → New Policy → Allow public read access
Step 2: Get Credentials
- Go to Settings → API
- Copy Project URL (SUPABASE_URL)
- Copy anon public key (SUPABASE_KEY)
Step 3: Configure Django
# settings.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
# Supabase Configuration
SUPABASE_URL = os.getenv('SUPABASE_URL')
SUPABASE_KEY = os.getenv('SUPABASE_KEY')
SUPABASE_MEDIA_BUCKET = os.getenv('SUPABASE_MEDIA_BUCKET', 'media')
SUPABASE_STATIC_BUCKET = os.getenv('SUPABASE_STATIC_BUCKET', 'static')
# Storage Configuration
STORAGES = {
'default': {
'BACKEND': 'django_supabase_storage.SupabaseMediaStorage',
},
'staticfiles': {
'BACKEND': 'django_supabase_storage.SupabaseStaticStorage',
},
}
# Static files URL for Supabase
STATIC_URL = f'{SUPABASE_URL}/storage/v1/object/public/{SUPABASE_STATIC_BUCKET}/'
# Media files URL for Supabase
MEDIA_URL = f'{SUPABASE_URL}/storage/v1/object/public/{SUPABASE_MEDIA_BUCKET}/'
Step 4: Use in Your Application
# models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
cover_image = models.ImageField(upload_to='articles/')
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='avatars/')
bio = models.TextField()
API Reference
SupabaseStorage Methods
# Save a file
path = storage.save('folder/filename.ext', content)
# Open/download a file
file_obj = storage.open('folder/filename.ext', mode='rb')
content = file_obj.read()
# Delete a file
storage.delete('folder/filename.ext')
# Check if file exists
exists = storage.exists('folder/filename.ext')
# List directory
dirs, files = storage.listdir('folder/')
# Get file size in bytes
size = storage.size('folder/filename.ext')
# Get public URL
url = storage.url('folder/filename.ext')
# Get file timestamps
created = storage.get_created_time('folder/filename.ext')
modified = storage.get_modified_time('folder/filename.ext')
accessed = storage.get_accessed_time('folder/filename.ext')
Troubleshooting
SUPABASE_URL or SUPABASE_KEY Not Configured
Error: ValueError: SUPABASE_URL is not configured!
Solution: Set environment variables or add to settings:
SUPABASE_URL = 'https://your-project-id.supabase.co'
SUPABASE_KEY = 'your-anon-public-key'
SUPABASE_BUCKET_NAME = 'your-supabase-bucket-name'
Files Not Uploading
Error: IOError: UPLOAD TO SUPABASE FAILED!
Solutions:
- Verify API credentials are correct
- Check bucket exists in Supabase
- Ensure bucket policies allow uploads
- Check network connectivity
Files Not Found
Error: FileNotFoundError: Failed to download file_name
Solutions:
- Verify file path is correct
- Check bucket name configuration
- Ensure file was successfully uploaded
Permission Denied
Error: IOError: Permission denied
Solutions:
- Go to Supabase Dashboard → Storage → Buckets
- Click the bucket → Policies
- Ensure public read access is enabled
Best Practices
- Use environment variables for sensitive credentials
- Set appropriate bucket policies (public read for media/static)
- Organize files with folders (avatars/, uploads/, etc.)
- Cache static files in CDN for better performance
- Monitor storage usage in Supabase dashboard
- Use Django's
get_absolute_url()for model file URLs - Use separate buckets for both static and media files
Support
For issues and questions:
- Open an issue on GitHub
- See INSTALLATION.md for detailed setup instructions
- Check CHANGELOG.md for version history
License
MIT License - see LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_supabase_storage-1.0.1.tar.gz.
File metadata
- Download URL: django_supabase_storage-1.0.1.tar.gz
- Upload date:
- Size: 23.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
474312baee5c8ecc7e8dda2eadd57ba6fee5a53ace00cdbf5fd91e23cc28bc0e
|
|
| MD5 |
3e173174bb547729d34579231e0580aa
|
|
| BLAKE2b-256 |
d6cc38dd0c9acd0ee7d8afc2585683d1f46759d28668e00c6b1b5ea176b234f6
|
Provenance
The following attestation bundles were made for django_supabase_storage-1.0.1.tar.gz:
Publisher:
release.yml on Madhav89755/django-supabase-storage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_supabase_storage-1.0.1.tar.gz -
Subject digest:
474312baee5c8ecc7e8dda2eadd57ba6fee5a53ace00cdbf5fd91e23cc28bc0e - Sigstore transparency entry: 895971751
- Sigstore integration time:
-
Permalink:
Madhav89755/django-supabase-storage@97133a7543db1954bb7cb274542d190934870057 -
Branch / Tag:
refs/tags/1.0.1 - Owner: https://github.com/Madhav89755
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@97133a7543db1954bb7cb274542d190934870057 -
Trigger Event:
release
-
Statement type:
File details
Details for the file django_supabase_storage-1.0.1-py3-none-any.whl.
File metadata
- Download URL: django_supabase_storage-1.0.1-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55fce047109eec4d279aa79ad706f07b5b7629e532e4e22b9e081a08b21a07c6
|
|
| MD5 |
6587a2cbc9649aefe549d04e0d947dd3
|
|
| BLAKE2b-256 |
9f6b396980459b0ca5a9c51d2796ad992a7e30e67dad05f1a52ec404ebdd3b26
|
Provenance
The following attestation bundles were made for django_supabase_storage-1.0.1-py3-none-any.whl:
Publisher:
release.yml on Madhav89755/django-supabase-storage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_supabase_storage-1.0.1-py3-none-any.whl -
Subject digest:
55fce047109eec4d279aa79ad706f07b5b7629e532e4e22b9e081a08b21a07c6 - Sigstore transparency entry: 895971788
- Sigstore integration time:
-
Permalink:
Madhav89755/django-supabase-storage@97133a7543db1954bb7cb274542d190934870057 -
Branch / Tag:
refs/tags/1.0.1 - Owner: https://github.com/Madhav89755
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@97133a7543db1954bb7cb274542d190934870057 -
Trigger Event:
release
-
Statement type: