개요배경ImageFieldFileFieldFileField.upload_toFieldFileStoragedjango-storagesdjango-storages를 통한 S3 버킷 사용django-storages에서 CloudFront 사용Django 파일 업로드와 AWS S3boto3References
이 포스트는 현재 작성중입니다
개요
Django의 ImageField에 대한 분석, 그리고 Django에서 AWS S3를 이용해 파일 저장을 하며 유연성을 가질 수 있는 방법을 정리한다.
배경
Django에서 파일 저장을 다루며, S3과 CloudFront를 사용했을 때 url을 유연하게 변경할 수 있는 방법을 찾고 ImageField에 정확히 어떤 방식으로 파일이 저장되는지, 크롤링 한 파일을 ImageField에 업로드할 obvious한 방법을 찾기 위해 이 글을 작성하며 지식을 정리해보기로 했다.
ImageField
class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)
ImageField
는 FileField
를 상속하며, FileField
에서 추가적으로 업로드 된 것이 유효한 이미지인지 검증하는 기능이 추가되있다.사용하려면 Pillow 라이브러리가 필요하다.
또한
ImageField.height_field
와 ImageField.width_field
를 가진다. width와 height로 접근 가능하다.# a 객체의 photo_file 필드가 ImageField이다 >>> a.photo_file <ImageFieldFile: review_pictures/460607af-c448-4fa0-828d-7e07341832bb.JPG> >>> a.photo_file.width 2049 >>> a.photo_file.height 1536
DB에서는 varchar(100) 필드로 경로가 저장된다. 기본값이 100으로 변경 가능하다.
그럼 이제
FileField
를 살펴보자.FileField
class FileField(upload_to='', storage=None, max_length=100, **options)
FileField.upload_to
class MyModel(models.Model): # file will be uploaded to MEDIA_ROOT/uploads upload = models.FileField(upload_to="uploads/") # file will be saved to MEDIA_ROOT/uploads/2015/01/30 upload = models.FileField(upload_to="uploads/%Y/%m/%d/")
upload_to
필드 지정을 통해 파일이 저장될 위치를 지정해줄 수 있다.해당 경로를 지정할 때
strftime()
시간 포매팅을 추가할 수 있다.DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' MEDIA_ROOT = '' MEDIA_URL = ''
upload_to
필드를 지정해주었을 때 Storage.save()
메소드로 전달되어 파일 저장위치가 전달된다.이때 기본
FileSystemStorage
를 사용한다면 MEDIA_ROOT
로 지정한 경로에 저장된다.이렇게 저장된 파일은
MEDIA_URL
에서 접속 가능하다.이때 이미지를 장고 서버로 직접 제공하면 비효율적이기에 보통 Nginx등의 웹서버를 통해서 서빙한다.
def custom_upload_to(instance, filename): ext = filename.split(".")[-1] filename = f"{uuid.uuid4()}.{ext}" # 파일명을 무작위 uuid로 변경, 확장자는 유지 return os.path.join("images", filename) # images/파일명.확장자를 반환한다 class Restaurant(models.Model): thumbnail = models.ImageField( upload_to=custom_upload_to, blank=True, null=True )
또한
upload_to
를 str 값이 아닌 함수로 지정해줄 수도 있다. 이때는 경로 뿐만 아니라, 파일명까지 포함된 값을 반환해주어야 한다.경로는 Unix-style의 경로를 사용해야한다(forward slash
/
를 사용해야 한다 \
가 아님!)FieldFile
모델의 FileField에 접근시 파일에 엑세스 하기 위한 프록시 FieldFile를 제공받는다.
>>> type(a.photo_file) <class 'django.db.models.fields.files.ImageFieldFile'>
FieldFile에서는 여러 메소드(필드)를 제공한다. 아래는 각 메소드의 설명과 실행 예시 값이다.
FieldFile.name
- 'images/460607af-c448-4fa0-828d-7e07341832bb.JPG’
FieldFile.path
- S3 사용으로 인해 오류 발생
FieldFile.size
: 크기를 바이트 단위로 반환- 837381
FieldFile.url
- 'https://bucket.s3.ap-northeast-2.amazonaws.com/images/460607af-c448-4fa0-828d-7e07341832bb.JPG'
FieldFile.open
(mode='rb')
FieldFile.close
()
FieldFile.save
(name, content, save=True)
FieldFile.delete
(save=True)
Storage
django-storages
django-storages는 Django에서 custom backend storages를 구성하는 것을 도와주는 라이브러리이다.
django-storages를 통한 S3 버킷 사용
다음 명령을 통해 django-storages와 AWS SDK인 boto3 라이브러리를 추가한다.
pip install django-storages boto3
이후 settings.py 를 수정해준다.
##### Django < 4.2의 경우 ##### DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" # 버킷 이름 지정 AWS_STORAGE_BUCKET_NAME = "bucket-name" ##### Django 4.2부터 바뀐 설정 방식 ##### STORAGES = { "default": { "BACKEND": "storages.backends.s3.S3Storage", "OPTIONS": { ...your_options_here }, }, }
django-storages에서 CloudFront 사용
AWS_S3_CUSTOM_DOMAIN
또는 custom_domain
옵션에 CloudFront 주소를 작성해주면 된다.AWS_S3_CUSTOM_DOMAIN="example.cloudfront.net"
다음과 같이 사용한다면 lambda로 리사이즈를 자동화 하고, 리사이즈 폴더로 지정할 수도 있다.
AWS_S3_CUSTOM_DOMAIN="example.cloudfront.net/resize"
Django 파일 업로드와 AWS S3
boto3
boto3는 파이썬 AWS SDK이다.
사용을 위해서는 다음과 같이 설치한다.
pip install boto3