All skills
jeffallan avatar

/django-storages-s3

@2bb8261
by jeffallanjeffallan/claude-skills12k stars
1,124

Use when configuring Django to store static and media files on AWS S3 with django-storages. Invoke when working with the STORAGES setting, S3 buckets, presigned URLs, CloudFront, or boto3-backed file storage in settings.py. Configures the Django 4.2+ STORAGES dict, public/private custom backends, presigned GET/POST URLs, IAM policies, and S3 mocking for tests. Trigger terms: django-storages, S3, boto3, S3Boto3Storage, STORAGES, presigned URL, CloudFront, media files, collectstatic, AWS_STORAGE_BUCKET_NAME.

Use this Skill: https://skilld.dev/gh/jeffallan/claude-skills/django-storages-s3

This session only. Nothing lands on disk.

referencescustom-backends.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Custom Storage Backends

Split storage by access level: public images served over the CDN, private documents accessed only through presigned URLs. There are two idiomatic ways to do this.

Option A — Named entries in the STORAGES dict (Django 4.2+)

Preferred on modern Django. Each named backend is just another key:

STORAGES = {
    "default": { ... },      # media uploads
    "staticfiles": { ... },  # static files
    "public_images": {
        "BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
        "OPTIONS": {
            "bucket_name": "mybucket-public",
            "region_name": AWS_S3_REGION_NAME,
            "default_acl": None,        # public access via bucket policy, not ACLs
            "querystring_auth": False,  # clean, unsigned URLs
            "file_overwrite": False,
            "location": "media/public",
        },
    },
    "private_files": {
        "BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
        "OPTIONS": {
            "bucket_name": "mybucket-private",
            "region_name": AWS_S3_REGION_NAME,
            "default_acl": None,        # access controlled by presigning, not ACLs
            "querystring_auth": True,   # .url() returns presigned URLs automatically
            "custom_domain": None,      # MUST be None for presigning to work
            "file_overwrite": False,
            "location": "media/private",
        },
    },
}

Do not use default_acl="public-read" / "private" here. Since April 2023, new S3 buckets ship with Object Ownership = Bucket owner enforced, which disables ACLs — any default_acl value other than None raises AccessControlListNotSupported at upload time. Make the public bucket public with a bucket policy (s3:GetObject on media/public/*) and keep the private bucket locked down, gating access through presigned URLs (querystring_auth=True). ACL string values only work on legacy buckets that explicitly re-enable ACLs (Object Ownership = ACLs enabled).

Reference a named backend on a model field:

from django.core.files.storage import storages
from django.db import models

class Document(models.Model):
    image = models.ImageField(storage=storages["public_images"])
    contract = models.FileField(storage=storages["private_files"])

storages["..."] is the Django 4.2+ accessor; it resolves lazily, so it is safe to reference at class-definition time.

Option B — Manual helper (all Django versions)

Useful on Django < 4.2 or when you want a single source of truth that is not the STORAGES dict. Define backends as plain dicts:

# settings.py
PUBLIC_IMAGE_BACKEND = {
    "class": "storages.backends.s3boto3.S3Boto3Storage",
    "options": {
        "bucket_name": "mybucket-public",
        "region_name": AWS_S3_REGION_NAME,
        "default_acl": None,        # public access via bucket policy, not ACLs
        "querystring_auth": False,
        "file_overwrite": False,
        "location": "media/public",
    },
}

PRIVATE_FILE_BACKEND = {
    "class": "storages.backends.s3boto3.S3Boto3Storage",
    "options": {
        "bucket_name": "mybucket-private",
        "region_name": AWS_S3_REGION_NAME,
        "default_acl": None,        # access controlled by presigning, not ACLs
        "querystring_auth": True,   # .url() returns presigned URLs automatically
        "custom_domain": None,      # Must be None for presigned URLs to work
        "file_overwrite": False,
        "location": "media/private",
    },
}

Instantiate a backend from a settings dict:

# myapp/storages.py
from django.conf import settings
from django.utils.module_loading import import_string

def get_storage(setting_name):
    config = getattr(settings, setting_name)
    storage_class = import_string(config["class"])
    return storage_class(**config.get("options", {}))
# models.py
from myapp.storages import get_storage

class Document(models.Model):
    image = models.ImageField(storage=get_storage("PUBLIC_IMAGE_BACKEND"))
    contract = models.FileField(storage=get_storage("PRIVATE_FILE_BACKEND"))

When to use which

Situation Use
Django 4.2+, backend is a fixed config Option A (STORAGES dict)
Django < 4.2 Option B (manual helper)
Backend chosen dynamically at runtime Option B

File Upload in Views

Saving a model with a populated file field uploads to S3 automatically — no explicit boto3 call:

# forms.py
from django import forms

class UploadForm(forms.Form):
    file = forms.FileField()

# views.py
from django.shortcuts import render, redirect

def upload_view(request):
    if request.method == "POST":
        form = UploadForm(request.POST, request.FILES)
        if form.is_valid():
            instance = Document(contract=form.cleaned_data["file"])
            instance.save()  # uploads to S3 via the field's storage backend
            return redirect("success")
    else:
        form = UploadForm()
    return render(request, "upload.html", {"form": form})

For large files (> 100 MB), prefer direct browser-to-S3 uploads with a presigned POST so the file never transits your Django server — see presigned-urls.md.

Source: SKILL.md on GitHub

No alerts1mo3 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    The skill is a secure and comprehensive reference for configuring Django with AWS S3 via django-storages. It actively promotes security best practices, such as using environment variables for credential management and implementing least-privilege IAM policies. No malicious patterns, obfuscation, or vulnerabilities were detected.

  • Socket1mo

    No alerts

  • Snyk1mo

    Risk: LOW · No issues

Signed by skilld at 2bb8261. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 2 months ago
Other metadata
metadata
{
  "author": "https://github.com/awais786",
  "version": "1.0.0",
  "domain": "backend",
  "triggers": "django-storages, S3, boto3, S3Boto3Storage, STORAGES, presigned URL, CloudFront, media files, collectstatic",
  "role": "specialist",
  "scope": "implementation",
  "output-format": "code",
  "related-skills": "django-expert"
}

README badge

README badge for jeffallan/claude-skills/django-storages-s3