[Django/DRF/S3] S3 객체에서 full url을 반환하지 않을 때

조오닭·2024년 11월 17일
1

예전에 했던 트러블슈팅 기록용~..~

나는 현재 프로젝트에서 사용되는 static 파일들을 AWS S3로 전송하고 있다.
사실 배포하지 않거나 EC2 인스턴스의 용량이 충분하다면, 해당 로컬 환경에서 바로 data가 저장되는 형태로 하면 되지만, 그게 아니면 파일을 따로 관리할 필요가 있다.

1. Django에서 S3 기본 설정


django settings.py에서 해당 설정은 다음과 같았다.

AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = env('AWS_STORAGE_BUCKET_NAME')
AWS_S3_CUSTOM_DOMAIN = AWS_STORAGE_BUCKET_NAME + ".s3.ap-northeast-2.amazonaws.com"

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

딱히 특별하게 설정할 코드가 없던 설정법이었다.
이렇게 설정해줬더니 잘 연결되고 파일도 잘 저장되었는데... 문제는 실제로 서버에 얹히고 사진을 불러오니 url이 잘못되었다.

https://{bucket_name}.s3.{region}.amazonaws.com/static/image/user/user1_profile.jpg

내 설정으로는 위와 같이 나와야 정상이고 s3 객체를 직접 들여다봤을 때에도 해당 url이 나오는데,

https://{bucket_name}.s3.{region}.amazonaws.com/user/user1_profile.jpg

이렇게 중간 경로인 static/image/ 이 사라진 문제점이었다.

2. 문제 해결


저렇게 설정했는데도 나와 같이 안 된 케이스가 극히 드물었고... 머리를 쥐어뜯던 중에 한 포럼을 발견하였다. -> 링크
포럼 글 중에서 주목해야할 것은 STATIC_ROOTSTATIC_URL의 차이점인데, KenWhitesell님께서 정리해주셨지만 크게 와닿지 않아 따로 검색을 해봤다.
그러다가 스택오버플로우 글을 보고 이해가 됐다! -> 링크

STATIC_ROOT vs STATIC_URL

django의 settings.py에 사용되는 변수 두 개, STATIC_ROOT와 STATIC_URL은 비슷하면서도 다르다.

공통점 : 두 개는 static 파일의 path를 custom하는 역할
STATIC_ROOT : django에서 collectstatic 할 때의 path
STATIC_URL : static file을 서버에 serve할 때의 path

나의 경우엔 file이 제대로 저장되지만 serve할 때 path가 다르게 나타나는 문제였으므로 STATIC_URL을 명시해줘야 했다.

그래서 코드는?

  1. STATIC_ROOT, MEDIA_ROOT 설정을 STATIC_URL, MEDIA_URL로 바꿨다.
  2. 이유는 모르겠지만...
    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' 이 이상하게 작동되지 않은 때가 많아서 S3Boto3Storage를 상속받아 custom storage class를 만들었다.
AWS_ACCESS_KEY_ID = env('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = env('AWS_STORAGE_BUCKET_NAME')
AWS_S3_CUSTOM_DOMAIN = AWS_STORAGE_BUCKET_NAME + ".s3.ap-northeast-2.amazonaws.com"
# 여기까지는 동일한 코드

# 여기서부터는 수정/추가된 코드
class StaticStorage(S3Boto3Storage):
    location = "static"
    default_acl = None


class MediaStorage(S3Boto3Storage):
    location = "media"
    default_acl = None
    file_overwrite = True


STORAGES = {
    'default': {'BACKEND': f'{project_name}.settings.StaticStorage'},
    'staticfiles': {'BACKEND': f'{project_name}.settings.MediaStorage'}
}
STATIC_URL = "https://%s/static/" % AWS_S3_CUSTOM_DOMAIN
MEDIA_URL = "https://%s/media/" % AWS_S3_CUSTOM_DOMAIN
profile
백엔드 응애

0개의 댓글

관련 채용 정보