- 이미지 업로드
- 이미지 Resizing
- 로컬에 남은 이미지 삭제
- (보너스) The messages framwork
+) 인스타그램에 이미지 여러 장 업로드하던 것처럼 기능 구현하고 싶다면?
- 모델 설계 (1:N)
- 뷰에서도 반복적으로 저장하게끔 로직 추가 (django modelform multiple images 검색)
+) 부트스트랩 폼을 커스텀하고 싶다면? (link)
-
2022-10-17 추가 구현 기능 (
div
영역 전체에 링크 걸기)- 하단 코드와 같이 링크를 걸고 싶은
div
에 style, onclick 속성 명시적으로 작성하기
<!-- articles/templates/articles/index.html --> {% for article in articles %} <div class="col-4" style="cursor: pointer;" onclick="location.href='{% url 'articles:detail' article.pk %}'"> <div class="card" style="width: 18rem;"> <img src="..." class="card-img-top" alt="..."> <div class="card-body"> <h5 class="card-title">{{ article.title }}</h5> <p class="card-text">익명1</p> </div> </div> </div> {% endfor %}
- 하단 코드와 같이 링크를 걸고 싶은
가장 먼저 생각해볼 부분은 이미지를 DB에 저장해야하기 때문에, 필드를 추가
그 다음, 우리가 사용자에게 입력 받을 때 ModelForm 을 사용하고 있기 때문에 이걸 수정해야겠다고 생각하는게 기본
python imaging library 를 활용하는 pillow library 설치해야 함
공식 문서 먼저 읽어보고 문서에서 요구하는 방식대로 설치하기 (link)
$ pip install Pillow
$ pip freeze > requirements.txt
# articles/models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=20)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
image = models.ImageField(upload_to='images/', blank=True)
# DB 반영
$ python manage.py makemigrations
$ python manage.py migrate
# articles/forms.py
# fields = ['image'] 누락되어 있었다면 추가
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__'
labels = {
'title': '제목',
'content' : '내용',
'image' : '이미지',
}
# articles/views.py
def create(request):
if request.method == 'POST':
# 수정된 코드 👇👇 ArticleForm(request.POST, request.FILES)
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article_form.save()
return redirect('articles:index')
else:
article_form = ArticleForm()
context = {
'article_form': article_form
}
return render(request, 'articles/new.html', context=context)
<!-- articles/templates/articles/new.html -->
<!--
추가 코드 : enctype="multipart/form-data"
-->
{% extends 'base.html' %}
{% load django_bootstrap5 %}
{% block content %}
<div class="row mt-5">
<h1 class="text-center">글쓰기</h1>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form article_form %}
{% bootstrap_button content="작성완료" button_type="submit" button_class="btn-primary" %}
</form>
</div>
{% endblock %}
<!-- articles/templates/articles/detail.html -->
<img src="{{ article.image.url }}" alt="{{ article.image }}" width="400" height="300">
MEDIA_ROOT
,MEDIA_URL
에 대한 공식 문서에서 확인하고settings.py
,urls.py
에 아래와 같은 코드 추가
# settings.py
# Media files (user uploaded files)
MEDIA_ROOT = BASE_DIR / 'images'
MEDIA_URL = '/media/'
# pjt/urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
서버에 업로드된 이미지들을 너무 좋은 해상도로 관리하면, 서버의 저장 공간도 늘어나고 페이지 로딩도 느리기 때문에 원본 그 자체를 쓰기보단 프로세싱 처리해서 서버에 저장하기
이미지 관련 다른 처리들도 공식 문서 보면서 따라해보기(워터마크 등)
$ pip install django-imagekit
$ pip freeze > requirements.txt
# settings.py
INSTALLED_APPS = [
...,
'imagekit',
]
# articles/models.py
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=20)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
image = ProcessedImageField(upload_to='images/', blank=True,
processors=[ResizeToFill(400, 300)],
format='JPEG',
options={'quality': 80})
# DB 반영
$ python manage.py makemigrations
$ python manage.py migrate
이미지 파일이 없는 게시글들은 눌렀을 때 에러가 뜨기 때문에, 조건문으로 이미지가 있을 때와 없을 때를 구분하기
<!-- articles/templates/articles/index.html -->
<div class="card">
{% if article.image %}
<img src="{{ article.thumbnail.url }}" class="card-img-top" alt="{{ article.thumbnail }}">
{% else %}
<img src="https://archive.org/download/no-photo-available/no-photo-available.png" class="card-img-top" alt="none">
{% endif %}
<div class="card-body">
<h5 class="card-title">{{ article.title }}</h5>
<p class="card-text">익명1</p>
</div>
</div>
<!-- articles/templates/articles/detail.html -->
<div>
{% if article.image %}
<img src="{{ article.image.url }}" alt="{{ article.image }}" width="400" height="300">
<p class="me-5 mt-3">{{ article.content }}</p>
{% else %}
<p class="me-5 mt-3">{{ article.content }}</p>
{% endif %}
</div>
create
함수처럼, 코드에request.FILES
추가
def update(request, pk):
article = Article.objects.get(pk=pk)
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES, instance=article)
if article_form.is_valid():
article_form.save()
return redirect('articles:detail', article.pk)
else:
article_form = ArticleForm(instance=article)
context = {
'article_form': article_form
}
return render(request, 'articles/update.html', context)
django-imagekit
사용해서 썸네일 만들기
- 원본 ImageField 로부터 생성 (원본O, 썸네일O) : ImageSpecField
- 원본 이미지를 재가공하여 저장 (원본X, 썸네일O) : ProcessedImageField
- 템플릿에서 이미지 직접 처리 (원본O)
# articles/models.py
from imagekit.models import ProcessedImageField, ImageSpecField
from imagekit.processors import ResizeToFill
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=20)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
image = ProcessedImageField(upload_to='images/', blank=True,
processors=[ResizeToFill(400, 300)],
format='JPEG',
options={'quality': 80})
thumbnail = ImageSpecField(source='image',
processor=[ResizeToFill(120,80)],
format='JPEG')
# DB 반영
$ python manage.py makemigrations
$ python manage.py migrate
<!-- articles/templates/articles/index.html -->
{% if article.thumbnail.url %}
<img src="{{ article.thumbnail.url }}" class="card-img-top" alt="{{ article.thumbnail }}">
{% endif %}
위 상태에서 이미지가 첨부된 게시글을 삭제해보면, 글은 지워져도 로컬에 이미지들이 남아있음
따라서
django-cleanup
패키지 설치해서 글이 삭제되었을 때 로컬에 남은 첨부 이미지들도 삭제될 수 있게 처리 (link)
$ pip install django-cleanup
$ pip freeze > requirements.txt
# pjt/settings.py
INSTALLED_APPS = (
...,
'django_cleanup.apps.CleanupConfig',
)
공식문서 : https://docs.djangoproject.com/en/4.1/ref/contrib/messages/
상세코드 : https://github.com/kdt-live/01-django-modelform/commit/d8e46dc179f730b6d3395581c7c97753f464ae0f
상세과정은 10.17 강의 2:44:54 참조 (추후 정리)