📝 Django Todo 프로젝트: 이미지 처리 + Summernote + Bootstrap5 통합 실습 정리
✅ 목표 요약
- django-summernote를 활용한 rich text 편집 기능 적용
- ImageField + Pillow로 이미지 썸네일 자동 생성 로직 구현
- django-cleanup으로 이미지 수정/삭제 시 파일 정리 자동화
- Bootstrap5 기반 Form UI 개선 및 정리
📦 필요한 라이브러리 설치
poetry add django-summernote pillow django-cleanup
그리고 settings.py에 다음 설정 추가:
INSTALLED_APPS = [
...
'django_summernote',
'django_cleanup.apps.CleanupConfig', # ✅ 파일 자동 삭제 처리
]
📌 Summernote 보안 설정 예시:
X_FRAME_OPTIONS = 'SAMEORIGIN'
SUMMERNOTE_CONFIG = {
'iframe': False,
'summernote': {
'disableDragAndDrop': True,
},
}
🧱 1. Todo 모델 수정하기
from django.db import models
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
from pathlib import Path
class Todo(models.Model):
...
completed_image = models.ImageField(upload_to='todo/images/', null=True, blank=True)
thumbnail = models.ImageField(upload_to='todo/thumbs/', null=True, blank=True, default='todo/thumbs/default.png')
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.completed_image:
image = Image.open(self.completed_image)
image.thumbnail((300, 300))
image_path = Path(self.completed_image.name)
filename_stem = image_path.stem
file_ext = image_path.suffix
thumb_name = f'{filename_stem}_thumb{file_ext}'
temp_thumb = BytesIO()
image.save(temp_thumb, format=image.format)
temp_thumb.seek(0)
self.thumbnail.save(thumb_name, ContentFile(temp_thumb.read()), save=False)
temp_thumb.close()
super().save(*args, **kwargs)
🧾 2. TodoForm, TodoUpdateForm 구성
from django import forms
from django_summernote.widgets import SummernoteWidget
from .models import Todo
class TodoForm(forms.ModelForm):
class Meta:
model = Todo
fields = '__all__'
widgets = {
'description': SummernoteWidget(),
'title': forms.TextInput(attrs={'class': 'form-control'}),
'start_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'end_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
}
class TodoUpdateForm(forms.ModelForm):
class Meta:
model = Todo
fields = '__all__'
widgets = {
'description': SummernoteWidget(),
'title': forms.TextInput(attrs={'class': 'form-control'}),
'start_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'end_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'is_completed': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'completed_image': forms.FileInput(attrs={'class': 'form-control'}),
}
⚙️ 3. cb_views.py 설정
from .forms import TodoForm, TodoUpdateForm
class TodoCreateView(CreateView):
model = Todo
form_class = TodoForm
class TodoUpdateView(UpdateView):
model = Todo
form_class = TodoUpdateForm
🛠 4. admin.py 설정
from django_summernote.admin import SummernoteModelAdmin
class TodoAdmin(SummernoteModelAdmin):
summernote_fields = ('description',)
fieldsets = (
(None, {'fields': ('title', 'description', 'completed_image', 'thumbnail')}),
)
🎨 5. 템플릿 수정 (todo_form.html 등)
📄 todo_list.html
{% for todo in todos %}
<div class="card">
<img src="{{ todo.thumbnail.url }}" class="card-img-top" alt="썸네일">
<div class="card-body">
<h5>{{ todo.title }} {% if todo.is_completed %}<span class="badge bg-success">Completed</span>{% endif %}</h5>
...
</div>
</div>
{% endfor %}
📄 todo_form.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">저장</button>
</form>
📌 todo_create.html, todo_update.html → {% include 'todo_form.html' %} 방식으로 구성하세요.
✅ 최종 체크리스트
- django-summernote 적용 및 XSS 방지 설정
- Pillow로 썸네일 자동 생성 로직 구현
- django-cleanup으로 이미지 정리 자동화
- Bootstrap5로 템플릿 UI 개선
- Form 및 Admin 최적화 구성 완료
필요시 미디어 루트 설정, static 경로, default 이미지 등록 위치까지 추가 안내 가능합니다 ✅
'과제' 카테고리의 다른 글
[To do list] Django Custom User + 이메일 인증 시스템 구현 가이드 1/2 (0) | 2025.05.13 |
---|---|
📌 Django Todo 프로젝트: 이미지 업로드 + 썸네일 생성 + Summernote 적용 전체 흐름 정리 (0) | 2025.05.12 |
📚 Django 프로젝트 시작하기 - 가상환경 구축부터 서버 실행까지 (0) | 2025.04.30 |
Flask practice blog 구축 인터페이스(UI) posts.html (3/3) (0) | 2025.04.22 |
Flask practice blog 구축 API 라우트 설정 posts_routes.py (2/3) (0) | 2025.04.22 |