Django ImageField와 S3 그리고 리사이징

Django ImageField와 S3 그리고 리사이징

Category
Published
August 2, 2024
Last updated
Last updated October 25, 2024
💡
이 포스트는 현재 작성중입니다

개요

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)
ImageFieldFileField를 상속하며, FileField에서 추가적으로 업로드 된 것이 유효한 이미지인지 검증하는 기능이 추가되있다.
사용하려면 Pillow 라이브러리가 필요하다.
또한 ImageField.height_fieldImageField.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으로 변경 가능하다.
notion image
notion image
그럼 이제 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 = ''
settings.py
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 }, }, }
settings.py

django-storages에서 CloudFront 사용

AWS_S3_CUSTOM_DOMAIN 또는 custom_domain 옵션에 CloudFront 주소를 작성해주면 된다.
AWS_S3_CUSTOM_DOMAIN="example.cloudfront.net"
settings.py
다음과 같이 사용한다면 lambda로 리사이즈를 자동화 하고, 리사이즈 폴더로 지정할 수도 있다.
AWS_S3_CUSTOM_DOMAIN="example.cloudfront.net/resize"
settings.py

Django 파일 업로드와 AWS S3

boto3

boto3는 파이썬 AWS SDK이다.
사용을 위해서는 다음과 같이 설치한다.
pip install boto3
 

References