반응형
이미지 최적화가 필요한 이유
초고화질인 이미지를 사용자가 업로드할 수 도 있다.
특히 갤러리의 경우 많은 이미지를 포함하게 되는데 위에 이미지와 같이 4.32MB 이상의 고용량의 이미지들이 누적되다 보면 그만큼의 리소스를 소비해야 한다. 따라서 이미지는 적당히 최적화할 필요성이 있다.
이미지 최적화 적용
helper.py
# 일관성 있게 이미지 저장
def uuid_name_upload_to(instance: models.Model, filename: str) -> str:
app_label = instance.__class__._meta.app_label
cls_name = instance.__class__.__name__.lower()
ymd_path = force_str(timezone.now().strftime("%Y/%m/%d"))
extension = splitext(filename)[-1].lower()
new_filename = uuid4().hex + extension # 32자리의 난수 생성
return "/".join((app_label, cls_name, ymd_path, new_filename)) # ex) accounts/profile/2024/04/25/filename
# 이미지 최적화
def make_thumb(
image_file: File, max_width: int = 1024, max_height: int = 1024, quality=80
) -> File:
pil_image = Image.open(image_file)
max_size = (max_width, max_height)
pil_image.thumbnail(max_size)
# 만약 이미지가 RGBA(알파 채널 포함) 모드라면 RGB 모드로 변환
if pil_image.mode == "RGBA":
pil_image = pil_image.convert("RGB")
thumb_name = splitext(image_file.name)[0] + ".jpg"
# 썸네일 파일 생성: 비어있는 ContentFile 객체 생성 후 이름 설정
thumb_file = ContentFile(b"", name=thumb_name)
# PIL을 사용하여 이미지를 JPEG 형식으로 저장하고 지정된 품질로 설정
pil_image.save(thumb_file, format="jpeg", quality=quality)
return thumb_file
이미지 최적화는 이미지를 사용하는 모델에서 재사용할 수 있게 helper 모듈을 준비해 준다.
model.py
class Profile(LifecycleModelMixin, models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
)
avatar = models.ImageField(upload_to=uuid_name_upload_to)
@hook(BEFORE_SAVE, when="avatar", has_changed=True)
def on_image_change(self):
if self.avatar:
image_width = self.avatar.width
image_extension = splitext(self.avatar.name)[-1].lower()
if image_width > 1024 or image_extension not in (".jpg", ".jpeg"):
thumb_file = make_thumb(self.avatar.file, 1024, 1024, 80)
self.avatar.save(thumb_file.name, thumb_file, save=False) # 모델 인스턴스에 저장
https://rsinger86.github.io/django-lifecycle/
django-lifecycle 라이브러리를 사용한다.
이미지가 저장되기 전 avatar필드의 변경사항이 있을 경우에만 호출되어 helper에서 정의한 함수를 이용해 이미지를 최적화한다.
실제 이미지를 저장하는 건 모델에서 처리할 거 기 때문에 avatar 필드를 업데이트만 해주고 저장은 수행하지 않는다.
이미지가 정상적으로 최적화되어 업로드된 것을 확인할 수 있다.
관련 커밋
https://github.com/bingual/django-5.0/commit/0019a090740a8d680225dfcac67d9642ef5f7763#diff-f6af2ff54b7b2982f691e19c61a9b92e22a98b70d50bef4e7c4af2ae032fb602
프로필, 프로필 수정 추가 · bingual/django-5.0@0019a09
bingual committed Apr 24, 2024
github.com
'기술정리 > Django' 카테고리의 다른 글
Django 다중 업로드 지원하기 (0) | 2024.05.06 |
---|---|
Django Race condition 문제 해결하기 (0) | 2024.04.28 |
Django 테이블 조회 n + 1 문제 해결하기 (1) | 2024.04.09 |
Django ManyToManyField 커스텀 모델 이전하기 (0) | 2024.04.08 |
Django slug 필드를 활용하여 검색하기 (0) | 2024.04.06 |