Skip to content

Commit b4e9135

Browse files
committed
feat: 미디어 파일 저장소 설정을 위한 환경 변수 및 .gitignore 업데이트
1 parent 34707f2 commit b4e9135

3 files changed

Lines changed: 67 additions & 23 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ django_extensions/*
249249
static
250250
static/*
251251

252+
# Django media (self-hosted FileSystemStorage uploads)
253+
media
254+
media/*
255+
252256
# Jupyter Notebook
253257
.ipynb_checkpoints
254258
.ipynb_checkpoints/*

app/core/settings.py

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import environ
88
import sentry_sdk
99
import sentry_sdk.integrations.django
10+
from django.core.exceptions import ImproperlyConfigured
1011

1112
# Build paths inside the project like this: BASE_DIR / 'subdir'.
1213
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
@@ -283,46 +284,66 @@
283284
# Static files (CSS, JavaScript, Images)
284285
# https://docs.djangoproject.com/en/5.2/howto/static-files/
285286
STATIC_ROOT = BASE_DIR / "static"
286-
MEDIA_ROOT = BASE_DIR / "media"
287+
# env 로 덮어쓰더라도 항상 pathlib.Path 로 유지한다. (env() 는 값이 설정되면 str 을 반환)
288+
MEDIA_ROOT = pathlib.Path(env("DJANGO_MEDIA_ROOT", default=BASE_DIR / "media"))
287289

288290
DATA_UPLOAD_MAX_MEMORY_SIZE = 30 * 1024 * 1024 # 30 MB
289291
FILE_UPLOAD_MAX_MEMORY_SIZE = 30 * 1024 * 1024 # 30 MB
290292

291-
DEFAULT_STORAGE_BACKEND = env("DJANGO_DEFAULT_STORAGE_BACKEND", default="storages.backends.s3.S3Storage")
292-
STATIC_STORAGE_BACKEND = env("DJANGO_STATIC_STORAGE_BACKEND", default="storages.backends.s3.S3Storage")
293+
S3_STORAGE_BACKEND = "storages.backends.s3.S3Storage"
294+
295+
DEFAULT_STORAGE_BACKEND = env("DJANGO_DEFAULT_STORAGE_BACKEND", default=S3_STORAGE_BACKEND)
296+
STATIC_STORAGE_BACKEND = env("DJANGO_STATIC_STORAGE_BACKEND", default=S3_STORAGE_BACKEND)
297+
298+
# AWS S3 모드일 때만 S3 전용 설정을 적용한다. (env 가 S3 백엔드를 가리키면 기존 동작을 그대로 유지)
299+
# 그 외(FileSystemStorage = 자체 호스팅) 모드에서는 로컬 파일시스템에 맞는 설정만 넣는다.
300+
USING_S3 = DEFAULT_STORAGE_BACKEND == S3_STORAGE_BACKEND
301+
302+
# default(media/public)와 static 백엔드는 함께 S3 이거나 함께 자체 호스팅이어야 한다.
303+
# 한쪽만 S3 로 두면 STORAGES["staticfiles"] 가 버킷 없이 구성되어 조용히 깨지므로 시작 시 막는다.
304+
if USING_S3 != (STATIC_STORAGE_BACKEND == S3_STORAGE_BACKEND):
305+
raise ImproperlyConfigured(
306+
"DJANGO_DEFAULT_STORAGE_BACKEND 와 DJANGO_STATIC_STORAGE_BACKEND 는 "
307+
"둘 다 S3 이거나 둘 다 비-S3(자체 호스팅) 여야 합니다. "
308+
f"(default={DEFAULT_STORAGE_BACKEND!r}, static={STATIC_STORAGE_BACKEND!r})"
309+
)
293310

294311
PRIVATE_STORAGE_BUCKET_NAME = f"pyconkr-backend-{API_STAGE}"
295312
PUBLIC_STORAGE_BUCKET_NAME = f"pyconkr-backend-{API_STAGE}-public"
296313

297-
STATIC_URL = (
298-
f"https://s3.ap-northeast-2.amazonaws.com/{PRIVATE_STORAGE_BUCKET_NAME}/"
299-
if STATIC_STORAGE_BACKEND == "storages.backends.s3.S3Storage"
300-
else "static/"
301-
)
302-
MEDIA_URL = (
303-
f"https://s3.ap-northeast-2.amazonaws.com/{PUBLIC_STORAGE_BUCKET_NAME}/"
304-
if DEFAULT_STORAGE_BACKEND == "storages.backends.s3.S3Storage"
305-
else "media/"
306-
)
314+
if USING_S3:
315+
STATIC_URL = f"https://s3.ap-northeast-2.amazonaws.com/{PRIVATE_STORAGE_BUCKET_NAME}/"
316+
MEDIA_URL = f"https://s3.ap-northeast-2.amazonaws.com/{PUBLIC_STORAGE_BUCKET_NAME}/"
307317

308-
STATIC_STORAGE_OPTIONS = (
309-
{
318+
STATIC_STORAGE_OPTIONS = {
310319
"bucket_name": PRIVATE_STORAGE_BUCKET_NAME,
311320
"file_overwrite": False,
312321
"addressing_style": "path",
313322
}
314-
if DEFAULT_STORAGE_BACKEND == "storages.backends.s3.S3Storage"
315-
else {}
316-
)
317-
PUBLIC_STORAGE_OPTIONS = (
318-
{
323+
PUBLIC_STORAGE_OPTIONS = {
319324
"bucket_name": PUBLIC_STORAGE_BUCKET_NAME,
320325
"file_overwrite": False,
321326
"addressing_style": "path",
322327
}
323-
if DEFAULT_STORAGE_BACKEND == "storages.backends.s3.S3Storage"
324-
else {}
325-
)
328+
else:
329+
# 자체 호스팅(FileSystemStorage): static·미디어 모두 nginx 가 서빙한다.
330+
# - static: collectstatic -> STATIC_ROOT, nginx 가 STATIC_URL 로 서빙.
331+
# - 미디어(public 업로드): PublicFile 은 upload_to="public/" 이므로 디스크 경로는 MEDIA_ROOT/public/<name>,
332+
# URL 은 MEDIA_URL + "public/<name>" 로 떨어진다. (location/base_url 기본값 = MEDIA_ROOT/MEDIA_URL)
333+
STATIC_URL = env("DJANGO_STATIC_URL", default="static/")
334+
MEDIA_URL = env("DJANGO_MEDIA_URL", default="media/")
335+
336+
# URL 뒤에 파일 경로가 그대로 이어붙으므로 끝 슬래시를 보장한다. (예: MEDIA_URL + "public/<name>")
337+
if not STATIC_URL.endswith("/"):
338+
STATIC_URL += "/"
339+
if not MEDIA_URL.endswith("/"):
340+
MEDIA_URL += "/"
341+
342+
# FileSystemStorage 등 로컬 백엔드에는 S3 전용 kwargs(bucket_name 등)를 넘기지 않는다.
343+
STATIC_STORAGE_OPTIONS = {}
344+
PUBLIC_STORAGE_OPTIONS = {}
345+
346+
# STORAGES 구조는 두 모드 공통이며, OPTIONS 만 위 분기에서 모드별로 채워진다.
326347
STORAGES = {
327348
"default": {"BACKEND": DEFAULT_STORAGE_BACKEND, "OPTIONS": STATIC_STORAGE_OPTIONS},
328349
"staticfiles": {"BACKEND": STATIC_STORAGE_BACKEND, "OPTIONS": STATIC_STORAGE_OPTIONS},

envfile/.env.docker

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
11
DATABASE_HOST=host.docker.internal
22
CELERY_BROKER_URL=redis://host.docker.internal:46379/0
33
CELERY_RESULT_BACKEND=redis://host.docker.internal:46379/1
4+
5+
# ──────────────────────────────────────────────────────────────────────────────
6+
# Object storage
7+
# ──────────────────────────────────────────────────────────────────────────────
8+
# 기본값(아래 변수를 모두 비워두면): AWS S3 (storages.backends.s3.S3Storage). 기존 동작 그대로.
9+
#
10+
# 자체 호스팅(로컬 파일시스템 + nginx)으로 전환하려면 아래 주석을 해제한다.
11+
# - 미디어(public 업로드)는 nginx 가 MEDIA_URL 로 서빙한다.
12+
# 디스크 경로: MEDIA_ROOT/public/<name> <-> URL: MEDIA_URL + "public/<name>"
13+
# nginx: location /media/ { alias <MEDIA_ROOT>/; } -> /media/public/<name> -> <MEDIA_ROOT>/public/<name>
14+
# - static(admin/DRF CSS,JS)도 nginx 가 STATIC_URL 로 서빙한다.
15+
# 배포 시 `python manage.py collectstatic --noinput` 필수. (결과물: STATIC_ROOT = <BASE_DIR>/static)
16+
# nginx: location /static/ { alias <STATIC_ROOT>/; }
17+
#
18+
# DJANGO_DEFAULT_STORAGE_BACKEND=django.core.files.storage.FileSystemStorage
19+
# DJANGO_STATIC_STORAGE_BACKEND=django.contrib.staticfiles.storage.StaticFilesStorage
20+
# DJANGO_MEDIA_ROOT=/app/media
21+
# DJANGO_MEDIA_URL=https://rest-api.pycon.kr/media/ # dev: https://rest-api-dev.pycon.kr/media/
22+
# DJANGO_STATIC_URL=https://rest-api.pycon.kr/static/ # dev: https://rest-api-dev.pycon.kr/static/

0 commit comments

Comments
 (0)