django-storages-s3
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDjango Storages S3
使用Django Storages对接AWS S3
Senior Django specialist for production-grade file storage on AWS S3 via and — public and private media, static files, presigned URLs, and CloudFront.
django-storagesboto3资深Django专家出品,通过和实现基于AWS S3的生产级文件存储方案——涵盖公共/私有媒体文件、静态文件、预签名URL及CloudFront配置。
django-storagesboto3When to Use This Skill
适用场景
- Serving static and/or media files from AWS S3 instead of the local filesystem
- Configuring the Django 4.2+ dict or legacy
STORAGESDEFAULT_FILE_STORAGE - Separating public (CDN-served) and private (presigned) file backends
- Generating presigned download or direct browser-to-S3 upload URLs
- Fronting S3 with CloudFront and writing a least-privilege IAM policy
- Migrating local /
FileFieldstorage to S3 without code changesImageField - Testing storage code without hitting S3
- 从AWS S3而非本地文件系统提供静态文件和/或媒体文件服务
- 配置Django 4.2+的字典或旧版
STORAGESDEFAULT_FILE_STORAGE - 分离公共(CDN分发)和私有(预签名访问)文件后端
- 生成预签名下载链接或浏览器直接上传至S3的URL
- 为S3配置CloudFront前端并编写最小权限IAM策略
- 将本地/
FileField存储迁移至S3且无需修改代码ImageField - 在不访问真实S3的情况下测试存储相关代码
Core Workflow
核心流程
- Install & register — ; add
pip install django-storages[s3] boto3to"storages"INSTALLED_APPS - Configure credentials — Load from env vars or rely on an attached IAM role; never hardcode
- Wire the dict — Set
STORAGES(media) anddefaultbackends with separatestaticfilesprefixeslocation - Add named backends — Split public vs. private buckets/ACLs as additional entries when needed
STORAGES - Verify & test — Run , confirm uploads land in S3, and mock S3 in tests with
collectstaticorInMemoryStoragemoto
- 安装与注册 — 执行;将
pip install django-storages[s3] boto3添加至"storages"INSTALLED_APPS - 配置凭证 — 从环境变量加载或依赖附加的IAM角色;绝对不要硬编码凭证
- 配置字典 — 设置
STORAGES(媒体文件)和default后端,并使用不同的staticfiles前缀location - 添加命名后端 — 必要时将公共/私有存储桶/ACL作为额外的条目拆分
STORAGES - 验证与测试 — 运行,确认上传文件已存入S3,并在测试中使用
collectstatic或InMemoryStorage模拟S3moto
Reference Guide
参考指南
Load detailed guidance based on context:
| Topic | Reference | Load When |
|---|---|---|
| Settings & STORAGES | | Core settings, 4.2+ vs legacy, CloudFront |
| Custom backends | | Public vs. private buckets, per-field storage |
| Presigned URLs | | Download links, direct browser uploads |
| Testing & IAM | | Mocking S3, IAM policy, common pitfalls |
根据上下文加载详细指导:
| 主题 | 参考文档 | 适用场景 |
|---|---|---|
| 设置与STORAGES配置 | | 核心设置、4.2+与旧版对比、CloudFront配置 |
| 自定义后端 | | 公共/私有存储桶、按字段配置存储 |
| 预签名URL | | 下载链接、浏览器直接上传 |
| 测试与IAM | | S3模拟、IAM策略、常见陷阱 |
Minimal Working Example
最简可用示例
The snippet below demonstrates the core MUST DO constraints: env-loaded credentials, dict, separate media/static locations, and on the media backend.
STORAGESdefault_acl=Nonepython
undefined以下代码片段展示了必须遵守的核心约束:从环境加载凭证、使用字典、分离媒体/静态文件路径、媒体后端设置。
STORAGESdefault_acl=Nonepython
undefinedsettings.py
settings.py
import os
AWS_STORAGE_BUCKET_NAME = os.environ["AWS_STORAGE_BUCKET_NAME"]
AWS_S3_REGION_NAME = os.environ.get("AWS_S3_REGION_NAME", "us-east-1")
AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_S3_REGION_NAME}.amazonaws.com"
import os
AWS_STORAGE_BUCKET_NAME = os.environ["AWS_STORAGE_BUCKET_NAME"]
AWS_S3_REGION_NAME = os.environ.get("AWS_S3_REGION_NAME", "us-east-1")
AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_S3_REGION_NAME}.amazonaws.com"
On EC2/ECS/Lambda, omit keys entirely — boto3 uses the attached IAM role.
在EC2/ECS/Lambda上,完全省略密钥 — boto3会使用附加的IAM角色。
STORAGES = {
"default": { # media uploads
"BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
"OPTIONS": {
"bucket_name": AWS_STORAGE_BUCKET_NAME,
"location": "media",
"default_acl": None, # rely on bucket policy, not per-object ACLs
"file_overwrite": False,
"querystring_auth": False, # public objects → clean URLs
},
},
"staticfiles": {
"BACKEND": "storages.backends.s3boto3.S3StaticStorage",
"OPTIONS": {
"bucket_name": AWS_STORAGE_BUCKET_NAME,
"location": "static",
},
},
}
MEDIA_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/media/"
STATIC_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/static/"
```pythonSTORAGES = {
"default": { # 媒体文件上传
"BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
"OPTIONS": {
"bucket_name": AWS_STORAGE_BUCKET_NAME,
"location": "media",
"default_acl": None, # 依赖存储桶策略,而非单个对象的ACL
"file_overwrite": False,
"querystring_auth": False, # 公共对象 → 简洁URL
},
},
"staticfiles": {
"BACKEND": "storages.backends.s3boto3.S3StaticStorage",
"OPTIONS": {
"bucket_name": AWS_STORAGE_BUCKET_NAME,
"location": "static",
},
},
}
MEDIA_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/media/"
STATIC_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/static/"
```pythonmodels.py — uploads go straight to S3 on save()
models.py — 保存时直接上传至S3
from django.db import models
class Document(models.Model):
file = models.FileField(upload_to="docs/") # uses STORAGES["default"]
undefinedfrom django.db import models
class Document(models.Model):
file = models.FileField(upload_to="docs/") # 使用STORAGES["default"]
undefinedAuditing an Existing Configuration
现有配置审计
When reviewing a project that already uses S3 (not greenfield), walk this
checklist — each item is a constraint below rephrased as "find X, confirm Y":
- Credentials — → confirm values come from
grep -rn "AWS_SECRET_ACCESS_KEY\|aws_secret" settings//os.environor an IAM role, never literals committed to the repo.django-environ - ACLs — → on buckets created after April 2023, every value must be
grep -rn "default_acl\|AWS_DEFAULT_ACL" .. AnyNone/"public-read"will raise"private"; public access belongs in a bucket policy.AccessControlListNotSupported - Storage backend — confirm Django 4.2+ uses the dict, not
STORAGES/DEFAULT_FILE_STORAGE(removed in Django 5.1, so silently ignored on 5.1/5.2/6.0); confirm the static class isSTATICFILES_STORAGE, not a fabricated name.S3StaticStorage - Locations — confirm (media) and
defaulthave distinctstaticfilesprefixes or buckets solocationnever collides with uploads.collectstatic - Region — confirm (or the global
region_name) matches the bucket's real region and thatAWS_S3_REGION_NAMEincludes the region segment for non-AWS_S3_CUSTOM_DOMAINbuckets.us-east-1 - Presigning — for private backends, confirm and
querystring_auth=True; confirm presignedcustom_domain=Noneresults aren't cached past.url().AWS_QUERYSTRING_EXPIRE - Overwrite cleanup — where , confirm replaced files are explicitly deleted (otherwise superseded objects leak).
file_overwrite=False - IAM — confirm the policy grants only on the bucket ARN, not broader S3 access.
Get/Put/Delete/ListBucket
当审查已使用S3的项目(而非新项目)时,遵循以下检查清单 — 每项都是将下方约束重新表述为“查找X,确认Y”:
- 凭证 — 执行→ 确认值来自
grep -rn "AWS_SECRET_ACCESS_KEY\|aws_secret" settings//os.environ或IAM角色,绝对不是提交到仓库的字面量。django-environ - ACL设置 — 执行→ 对于2023年4月之后创建的存储桶,所有值必须为
grep -rn "default_acl\|AWS_DEFAULT_ACL" .。任何None/"public-read"都会触发"private"错误;公共访问应配置在存储桶策略中。AccessControlListNotSupported - 存储后端 — 确认Django 4.2+使用字典,而非
STORAGES/DEFAULT_FILE_STORAGE(这些在Django 5.1中已移除,因此在5.1/5.2/6.0中会被静默忽略);确认静态文件使用的类是STATICFILES_STORAGE,而非自定义名称。S3StaticStorage - 路径设置 — 确认(媒体文件)和
default有不同的staticfiles前缀或不同的存储桶,确保location不会与上传文件冲突。collectstatic - 区域设置 — 确认(或全局
region_name)与存储桶的实际区域匹配,并且对于非AWS_S3_REGION_NAME存储桶,us-east-1包含区域段。AWS_S3_CUSTOM_DOMAIN - 预签名配置 — 对于私有后端,确认且
querystring_auth=True;确认预签名的custom_domain=None结果不会缓存超过.url()时长。AWS_QUERYSTRING_EXPIRE - 覆盖清理 — 当时,确认替换的文件已被显式删除(否则会残留过期对象)。
file_overwrite=False - IAM权限 — 确认策略仅授予存储桶ARN上的权限,而非更宽泛的S3访问权限。
Get/Put/Delete/ListBucket
Constraints
约束规范
MUST DO
必须遵守
- Load AWS credentials from environment variables or an attached IAM role
- Set so bucket policies (not object ACLs) control access
default_acl=None - Give static and media files separate prefixes or separate buckets
location - Use the dict on Django 4.2+ (same config through 5.2 LTS and 6.0);
STORAGES/DEFAULT_FILE_STORAGEwere removed in 5.1, so reserve them for < 4.2 onlySTATICFILES_STORAGE - Set on any backend that issues presigned URLs
custom_domain=None - Mock S3 (or
InMemoryStorage) in tests instead of hitting real bucketsmoto
- 从环境变量或附加的IAM角色加载AWS凭证
- 设置,通过存储桶策略(而非对象ACL)控制访问
default_acl=None - 为静态文件和媒体文件设置不同的前缀或使用不同的存储桶
location - 在Django 4.2+上使用字典(该配置兼容5.2 LTS和6.0版本);
STORAGES/DEFAULT_FILE_STORAGE已在5.1中移除,仅在Django <4.2版本中使用STATICFILES_STORAGE - 对任何生成预签名URL的后端设置
custom_domain=None - 在测试中模拟S3(使用或
InMemoryStorage),而非访问真实存储桶moto
MUST NOT DO
禁止操作
- Hardcode in
AWS_SECRET_ACCESS_KEYor commit itsettings.py - Mix with a
querystring_auth=True(presigning breaks)custom_domain - Mix static and media files under the same prefix
- Grant the IAM user broader than on the bucket ARN
Get/Put/Delete/ListBucket - Rely on per-object ACLs on buckets created after April 2023 (ACLs disabled by default)
- 在中硬编码
settings.py或提交到仓库AWS_SECRET_ACCESS_KEY - 同时设置和
querystring_auth=True(预签名功能会失效)custom_domain - 将静态文件和媒体文件放在同一前缀下
- 为IAM用户授予存储桶ARN以外的更宽泛S3访问权限
- 在2023年4月之后创建的存储桶上依赖单个对象的ACL(默认禁用ACL)
Knowledge Reference
知识参考
django-storages, S3Boto3Storage, S3StaticStorage, boto3, STORAGES dict, presigned URLs, generate_presigned_post, CloudFront, IAM policy, InMemoryStorage, moto
django-storages, S3Boto3Storage, S3StaticStorage, boto3, STORAGES dict, presigned URLs, generate_presigned_post, CloudFront, IAM policy, InMemoryStorage, moto
Related Skills
相关技能
- — core Django models, DRF, and ORM that produce the files this skill persists to S3
django-expert - — secure end-to-end upload flows and access control around stored files
fullstack-guardian - — provisioning the S3 buckets, IAM roles, and CloudFront distributions this skill targets
devops-engineer
- — 核心Django模型、DRF和ORM,负责生成本技能需存储到S3的文件
django-expert - — 安全的端到端上传流程及存储文件的访问控制
fullstack-guardian - — 配置本技能所需的S3存储桶、IAM角色和CloudFront分发
devops-engineer