본문 이미지는 올렸는데 글 목록의 대표 이미지는 비어 있어, 저장한 글을 다시 열어 썸네일을 지정하던 문제가 있었습니다. 원래 이 글은 그 불편을 줄이려고 썸네일 선택 영역을 추가한 기록입니다. 당시의 작업 배경을 남기고, 2026년 9월 20일 현재 저장소에서 확인한 선택·저장 규칙을 덧붙였습니다.
본문 이미지와 대표 이미지를 따로 저장하는 이유
본문에는 여러 장의 화면을 넣을 수 있지만 목록에서는 한 장이 글을 대표합니다. 첫 이미지가 설명용 화면이고 두 번째 이미지가 완성 결과라면, 두 번째 이미지를 대표로 고를 수 있어야 합니다.
현재 Post.content에는 본문 HTML을, Post.thumbnail에는 선택한 이미지의 주소를 저장합니다. 썸네일을 선택할 때 이미지 파일을 다시 업로드하거나 별도 축소 파일을 만드는 구조는 아닙니다. 본문에 이미 들어 있는 파일의 주소를 대표 이미지 필드에서 다시 사용하는 방식입니다.

위 이미지는 이 글을 처음 작성할 때 사용한 화면입니다. 당시에는 Toast UI 에디터를 사용했고, 현재 관리자 v2 편집 화면은 본문 HTML에서 후보를 추출합니다. 아래 설명은 현재 v2 코드 기준입니다.
후보 추출 → 선택 유지 → 저장
현재 글쓰기·수정 템플릿의 extractImageUrlsFromHtml()은 임시 DOM에서 img[src]를 찾습니다. 빈 주소를 버리고 앞뒤 공백을 제거하며, data:image/로 시작하는 임시 이미지는 제외합니다. 같은 주소가 여러 번 나오면 Set으로 중복을 제거합니다.
const urls = Array.from(wrapper.querySelectorAll("img[src]"))
.map(img => img.getAttribute("src"))
.filter(Boolean)
.map(url => url.trim())
.filter(url => !url.startsWith("data:image/"));
return [...new Set(urls)];
renderThumbnailList()는 후보를 다시 그릴 때 현재 선택값을 먼저 읽습니다. 선택했던 주소가 여전히 본문에 있으면 그대로 유지하고, 없으면 본문 순서상 첫 번째 후보를 선택합니다. 이미지가 하나도 없으면 선택값도 빈 문자열로 지웁니다.
여기서 ‘첫 번째’는 현재 본문에서 먼저 등장하는 이미지입니다. 업로드한 시각을 DB에서 비교하는 방식이 아니므로 본문 이미지 순서를 바꾸면 기본 후보도 달라질 수 있습니다.
| 편집 상태 | 후보 목록 | 선택 결과 |
|---|---|---|
| A 이미지를 처음 추가 | A | A 자동 선택 |
| A 다음에 B를 추가 | A, B | 기존 선택 A 유지 |
| B를 클릭한 뒤 글을 더 작성 | A, B | B 유지 |
| 선택했던 B를 본문에서 삭제 | A | A로 변경 |
| 같은 A를 본문에 두 번 삽입 | A | 후보는 한 개 |
| 모든 이미지를 삭제 | 없음 | 썸네일 주소도 비움 |
이 표는 현재 코드의 분기 규칙을 정리한 것으로, 처리 속도나 사용자 작업 시간의 실측 결과는 아닙니다.
서버에서는 선택값을 어디에 넣나
화면에서 고른 주소는 숨겨진 입력 selected_thumbnail에 들어갑니다. 글쓰기 요청은 이 값을 새 글의 thumbnail에 넣고, 수정 요청은 기존 글의 thumbnail을 갱신합니다. 그래서 썸네일 후보의 선택 표시만 바꾸고 실제 입력값을 바꾸지 않으면 저장 후 목록에 반영되지 않습니다.
현재 저장소의 확인 위치는 다음과 같습니다.
blog/templates/blog/manager/content_write_v2.html: 후보 추출, 최초 선택, 저장 요청.blog/templates/blog/manager/post_edit_v2.html: 기존 선택 복원과 편집 중 후보 갱신.blog/manager/views.py:content_write_v2(),post_edit_v2()의selected_thumbnail저장.blog/models.py:Post.thumbnail필드.
같은 기능을 점검할 때의 순서
- 서로 다른 이미지 두 장을 본문에 넣고 두 번째 이미지를 선택합니다.
- 글을 저장한 뒤 목록과 수정 화면에서 같은 이미지가 선택되는지 확인합니다.
- 선택된 이미지를 본문에서 삭제하고, 남은 첫 이미지로 전환되는지 확인합니다.
- 이미지를 모두 삭제한 뒤 저장하고 이전 썸네일 주소가 남지 않는지 확인합니다.
- 화면은 맞는데 목록 이미지가 깨지면 저장값뿐 아니라 해당 이미지 URL이 실제로 열리는지 확인합니다.
후보에 나타난다는 사실만으로 파일이 유효하거나 계속 보관된다는 뜻은 아닙니다. 서버의 현재 저장 로직은 제출된 썸네일 주소를 저장하므로, 파일 접근 권한·허용 주소·본문과의 일치 여부 검증은 별도로 점검할 부분입니다. 또한 대표 이미지를 작게 표시하는 것과 실제 이미지 용량을 줄이는 것은 다릅니다. 큰 원본을 그대로 올렸다면 이미지 압축 도구에서 해상도와 출력 용량을 먼저 확인할 수 있습니다.
게시글 아래의 방문자 상호작용은 비회원 댓글과 답글 구현 기록에서 이어서 다룹니다.
첫 댓글을 남겨보세요.