|
7 | 7 | import environ |
8 | 8 | import sentry_sdk |
9 | 9 | import sentry_sdk.integrations.django |
| 10 | +from django.core.exceptions import ImproperlyConfigured |
10 | 11 |
|
11 | 12 | # Build paths inside the project like this: BASE_DIR / 'subdir'. |
12 | 13 | BASE_DIR = pathlib.Path(__file__).resolve().parent.parent |
|
283 | 284 | # Static files (CSS, JavaScript, Images) |
284 | 285 | # https://docs.djangoproject.com/en/5.2/howto/static-files/ |
285 | 286 | 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")) |
287 | 289 |
|
288 | 290 | DATA_UPLOAD_MAX_MEMORY_SIZE = 30 * 1024 * 1024 # 30 MB |
289 | 291 | FILE_UPLOAD_MAX_MEMORY_SIZE = 30 * 1024 * 1024 # 30 MB |
290 | 292 |
|
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 | + ) |
293 | 310 |
|
294 | 311 | PRIVATE_STORAGE_BUCKET_NAME = f"pyconkr-backend-{API_STAGE}" |
295 | 312 | PUBLIC_STORAGE_BUCKET_NAME = f"pyconkr-backend-{API_STAGE}-public" |
296 | 313 |
|
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}/" |
307 | 317 |
|
308 | | -STATIC_STORAGE_OPTIONS = ( |
309 | | - { |
| 318 | + STATIC_STORAGE_OPTIONS = { |
310 | 319 | "bucket_name": PRIVATE_STORAGE_BUCKET_NAME, |
311 | 320 | "file_overwrite": False, |
312 | 321 | "addressing_style": "path", |
313 | 322 | } |
314 | | - if DEFAULT_STORAGE_BACKEND == "storages.backends.s3.S3Storage" |
315 | | - else {} |
316 | | -) |
317 | | -PUBLIC_STORAGE_OPTIONS = ( |
318 | | - { |
| 323 | + PUBLIC_STORAGE_OPTIONS = { |
319 | 324 | "bucket_name": PUBLIC_STORAGE_BUCKET_NAME, |
320 | 325 | "file_overwrite": False, |
321 | 326 | "addressing_style": "path", |
322 | 327 | } |
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 만 위 분기에서 모드별로 채워진다. |
326 | 347 | STORAGES = { |
327 | 348 | "default": {"BACKEND": DEFAULT_STORAGE_BACKEND, "OPTIONS": STATIC_STORAGE_OPTIONS}, |
328 | 349 | "staticfiles": {"BACKEND": STATIC_STORAGE_BACKEND, "OPTIONS": STATIC_STORAGE_OPTIONS}, |
|
0 commit comments