인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

pplkjh2님의 프로필 이미지
pplkjh2

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)

11-16 프로필 이미지를 Pillow 라이브러리로 직접 썸네일 처리하고 JPEG로 변환하여, 이미지 크기 98% 줄이기

11-15) 프로필 수정에서 이미지 저장 시 문제

해결된 질문

작성

·

130

·

수정됨

0

  • 질문을 온전히 이해할 수 있도록, 모든 맥락을 전달해주세요.

  • 질문은 질문자가 번거로워야 보다 좋은 답변을 얻으실 수 있습니다.

  • 시행착오를 알려주시면 곧바로 원하는 문제에 집중할 수 있습니다.

  • 오류 메시지는 일부만 알려주시기보다 전체 오류 메시지를 캡처해서 주시면, 오류 파악에 도움이 됩니다.

     

당신의 파이썬/장고 페이스메이커가 되겠습니다. ;-)


인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.

 

 

11-15 강의에서 구현한 프로필 수정 폼에서 이미지를 올린 경우, 다시 프로필 수정 페이지에 들어가면 정상적으로 이전에 등록된 이미지가 현재란에 보여집니다. 이렇게 구현된 모델은 문제가 몇 가지 있는데요.

  1. 수정하지 않고 저장을 누를 경우 이전 강의에서 교육하신 내용처럼 접미사가 계속 바뀌어가면서 같은 내용의 파일이 spamming 되는 문제가 발생합니다.
    우리가 만약 프로필에 다른 항목이 추가된다면, 다른 항목만 수정하지 않고 나가는 유저가 있을텐데 해당 문제를

    해결하려면 어떻게 해야할까요?

  2. 수정 혹은 취소 체크 박스를 선택하여 삭제를 할 경우 여전히 경로 안에 파일이 남아 있습니다. signal을 이용하면 될 것 같은데, 하기와 같은 방법을 생각해 볼 수 있을까요?

    @receiver(pre_save, sender=Profile)
    def edit_delete_on_profile(instance=Profile, **kwargs):
        instance.avatar.delete(save=False)
  3. 수업 내용과는 상관없지만, 기본 제공되는 이미지 업로드 양식이 어색합니다. 특히 취소 체크 박스를 체크하여 제거하는 방식은 너무 어색한데요. 더 좋은게 없을까요? 예를들어 아래는 네이버 '치지직' 에서 프로필 수정 양식입니다.

    image.png


답변 3

0

이진석님의 프로필 이미지
이진석
지식공유자

그리고, Profile 모델 인스턴스 삭제 시에도 대응할려면, 아래와 같이 처리하실 수 있습니다.

@hook(AFTER_DELETE)
def on_after_delete(self):
    if self.avatar:
       self.avatar.delete(save=False)

0

이진석님의 프로필 이미지
이진석
지식공유자

세번째 문의 주신 내용에 대해서, 아래의 gist에 샘플 코드를 작성해서 공유해두었습니다.

https://gist.github.com/allieus/8807520f018b742d66f40ff0520f651f

이를 적용하시면, 아래와 같이 동작합니다.

image.png

django-crispy-forms 를 사용하면, 각 폼 필드는 django-crispy-forms의 CRISPY_TEMPLATE_PACK 설정에 지정한 (우리는 "bootstrap5"를 지정했고, 이는 crispy-bootstrap5 라이브러리를 사용합니다.) 템플릿을 사용합니다.

django-crispy-forms에서는 장고의 위젯 대신 Layout을 사용합니다. Div, Submit 모두 Layout 입니다. 다른 폼 필드 렌더링이 필요하시다면, 커스텀 Layout을 통해 커스터마이징하실 수 있습니다.

말씀하신 상황을 구현하기 위해서는 JS 적용이 필수적인데요. 장고 템플릿 내에서 추가적인 bundler없이 JS를 사용할려면, React 적용은 좀 번거롭습니다. 해외의 장고 커뮤니티에서 인기를 끌고 있는 JS 라이브러리가 alpine.js 입니다. vue.js 와 비슷하게 동작하지만 용량은 10KB로서 훨씬 작습니다.

위 내용과 링크를 참고해보시고, 추가 질문 있으시면 댓글 남겨주세요.

화이팅입니다. :-)

0

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

먼저 좋은 질문을 남겨주셔서 감사드립니다. :-)

 

답변 1. 폼 수정없이 ProfileForm 저장 시에 새로운 파일로 저장되는 부분은 clean_avatar 메서드의 버그입니다. 폼 수정없이도 self.cleaned_data 사전에는 instance 모델 객체의 avatar 초기값이 저장되어있는데요. 이 값으로 매번 PIL을 통해서 파일을 생성해서 발생한 이슈입니다.

아래와 같이 avatar 필드 값의 변화가 있을 때에만 썸네일 처리를 해주시면 해당 이슈는 해결될 것입니다.

image.png

그리고, 본 예시는 Form 코드 내에서도 직접 썸네일 처리를 할 수 있음을 보여드리기 위함이었구요. 썸네일 처리를 도와주는 django-imagekit 라이브러리가 있습니다. 이를 쓰시면 보다 간결하게 모델 필드 선언 만으로 썸네일 처리를 보다 유연하게 처리하실 수 있습니다.

 

답변 2. 파일 폼 필드의 "취소" 버튼은 ClearableFileInput 위젯을 통해서 만들어지는 데요. 취소 버튼이 클릭되어 폼 전송되면, 유효성 검사 단계에서 self.cleaned_data 사전 객체에 담겨지는 값만 제거할 뿐 입니다. // 장고에서는 FileField/ImageField를 통해 저장되는 파일이 다른 애플리케이션에서 참조될 수도 있고, 파일이 클라우드 스토리지에 저장되어있을 경우 삭제에 시간이 다소 걸릴 수 있습니다. 그래서 기본 동작으로는 파일을 삭제하지 않습니다.

매번 취소나 파일 변경 시에 파일이 자동 삭제토록 하실려면 말씀하신 대로 signals를 통해 처리하실 수 있는 데요. avatar 파일의 변경 여부를 탐지해야 하니, 이때에는 아래와 같이 django-lifecycle을 활용하시면 편리합니다.

image.png

참고로 장고에서는 추상화된 파일 스토리지 API를 지원하구요. 아래와 같이 작성하신다면 로컬 파일 시스템 외에도 aws s3 등의 클라우드 스토리지를 사용하시더라도, 파일 삭제가 됩니다.

django-cleanup 라이브러리를 통해서 배치성 작업으로 FileField/ImageField에 의해 참조되지 않는 파일들을 일괄삭제할 수 있습니다. 저는 이 접근을 추천드립니다.

 

답변 3. ProfileForm에서는 장고의 기본 위젯을 썼구요. ClearableFileInput 위젯이며 HTML 만으로 구현이 되어있고, crispy-bootstrap5 라이브러리를 통해 스타일이 조금 변경된 수준입니다.

보여주신 네이버 치지직에서의 프로필 양식의 경우 HTML 뿐만 아니라 JavaScript 구현이 필요한 경우로 보여집니다. 이를 위해 커스텀 위젯 구현이 필요해보이는데요. 본 강의 내용에 맞춰 어떤 접근이 좋을 지 고민을 해보고, 추가 댓글로 남기도록 하겠습니다. :-)

pplkjh2님의 프로필 이미지
pplkjh2
질문자

django-imagekit과 django-cleanup 라이브러리를 사용하니까 편리하게 구현하였습니다. 특히 cleanup 라이브러리는 셋팅도 쉬워서 좋고 추가로 가르쳐주신 hook을 사용하지 않아도 되서 좋네요.

alpine.js는 설명을 잘 해주셔서 적용하는 것에는 성공하였습니다만 아직 js가 익숙치 않아서 그런지 설명을 봐도 어렵네요.

친절하게 답변해주셔서 감사합니다.

pplkjh2님의 프로필 이미지
pplkjh2

작성한 질문수

질문하기