자바스크립트 입문

9. 자바스크립트로 보는 이미지 미리보기 기능 (feat. Django)

수달1234 2025. 5. 7. 17:17

시작

Django 웹 애플리케이션에서 JavaScript를 활용하여 이미지 미리보기 기능을 구현하는 방법을 소개합니다. 사용자가 이미지를 업로드하기 전에 어떤 이미지가 선택되었는지 미리 볼 수 있게 해주는 기능으로, 사용자 경험을 크게 향상시킬 수 있습니다.

 

Django 모델 설정

게시글 모델에 이미지 필드를 추가해야합니다.

class Post(models.Model):
	### 기존 코드들##
    image = models.ImageField(upload_to="posts/", blank=True, null=True) # 이미지

    def __str__(self):
        return self.title

 

모델을 수정하였으므로 마이그레이션을 진행해야합니다.

python manage.py makemigrations
python manage.py migrate

 

뷰 함수 설정

게시글 작성 함수에 이제 이미지 파일 처리를 추가해야합니다.

@login_required
def post_create(request):
    """게시글 작성"""
    if request.method == "POST":
        title = request.POST["title"]
        content = request.POST["content"]
        post = Post.objects.create(title=title, content=content, author=request.user)
        # 이미지가 있으면 저장
        if 'image' in request.FILES:
            post.image = request.FILES['image']
            post.save()
        return redirect("post_list")

    return render(request, "posts/post_form.html")

HTML 템플릿 작성

게시글 작성 폼 html에 이미지 업로드 및 미리보기 영역을 추가해야합니다.

        <div id="image-preview-container" style="margin-top: 10px; display: none;"
             data-has-image="{% if post.image %}true{% else %}false{% endif %}"
             data-image-url="{% if post.image %}{{ post.image.url }}{% endif %}">
            <img id="image-preview" style="max-width: 200px; max-height: 200px;">
        </div>
  • data-has-image : Django 템플릿 태그(if문 부분)를 사용하여 게시글에 이미지가 있는지(true,false) 여부를 저장합니다.
  • data-image-url : 이미자가 있을 경우 해당 이미지의 url을 가져와 저장합니다.

JavaScript 구현

document.addEventListener('DOMContentLoaded', function() {
    const imageInput = document.getElementById('image');
    const previewContainer = document.getElementById('image-preview-container');
    const previewImage = document.getElementById('image-preview');
    
    if (!imageInput || !previewContainer || !previewImage) return;
    
    imageInput.addEventListener('change', function() {
        if (this.files && this.files[0]) {
            const reader = new FileReader();
            
            reader.onload = function(e) {
                previewImage.src = e.target.result;
                previewContainer.style.display = 'block';
            };
            
            reader.readAsDataURL(this.files[0]);
        } else {
            if (previewContainer.getAttribute('data-has-image') === 'true') {
                previewImage.src = previewContainer.getAttribute('data-image-url');
                previewContainer.style.display = 'block';
            } else {
                previewContainer.style.display = 'none';
                previewImage.src = '';
            }
        }
    });
});

 

  • DOMContentLoaded 이벤트 리스너:
    • 페이지의 HTML이 완전히 로드되고 DOM 트리가 구성된 후 실행됩니다.
    • 이렇게 하면 스크립트가 참조하는 HTML 요소들이 확실히 존재하는 상태에서 코드가 실행됩니다.
  • 필요한 DOM 요소 가져오기:
    • imageInput: 파일 선택 입력 요소 (type="file")
    • previewContainer: 이미지 미리보기를 담을 컨테이너 div
    • previewImage: 실제 이미지가 표시될 img 요소
  • 요소 존재 확인:
    • 필요한 요소 중 하나라도 없으면 함수를 종료합니다.
    • 이는 오류 방지를 위한 안전장치입니다.
  • 파일 선택 이벤트 리스너:
    • 사용자가 파일 입력 필드에서 파일을 선택하거나 변경할 때 실행됩니다.
    • change 이벤트는 파일 선택, 취소 또는 변경 시 발생합니다.
  • 파일 선택 여부 확인:
    • this.files && this.files[0]: 파일이 하나 이상 선택되었는지 확인합니다.
    • 파일이 선택되었을 때와 선택되지 않았을 때에 따라 다른 처리를 합니다.
  • 파일이 선택된 경우 (if 블록):
    • FileReader 객체를 생성합니다. 이 API는 파일의 내용을 비동기적으로 읽기 위해 사용됩니다.
    • reader.onload: 파일 읽기가 완료되면 실행될 콜백 함수를 정의합니다.
    • reader.readAsDataURL(): 선택된 파일을 Data URL 형식으로 읽습니다. 이는 이미지를 Base64로 인코딩된 문자열로 변환합니다.
    • 파일 읽기가 완료되면 결과(e.target.result)를 이미지의 src 속성에 설정하고, 미리보기 컨테이너를 표시합니다.
  • 파일 선택이 취소된 경우 (else 블록):
    • data-has-image 속성을 확인하여 기존 이미지가 있는지 확인합니다.
    • 기존 이미지가 있으면(수정 모드):
      • data-image-url 속성에서 기존 이미지 URL을 가져와 미리보기 이미지에 설정합니다.
      • 미리보기 컨테이너를 표시합니다.
    • 기존 이미지가 없으면(새 게시글 모드):
      • 미리보기 컨테이너를 숨깁니다.
      • 이미지 소스를 비웁니다.

결론

Django와 JavaScript를 결합하여 이미지 미리보기 기능을 구현해 보았습니다. 이 기능은 사용자 경험을 향상시키는 간단하면서도 효과적인 방법입니다. 사용자는 이미지를 업로드하기 전에 어떤 이미지가 선택되었는지 확인할 수 있어 잘못된 이미지 업로드를 방지할 수 있습니다.

아래의 사진처럼 이미지를 넣으면 즉시 사진의 미리보기를 제공하는것을 알 수 있습니다.

테스트 사진