Django(11) - 이미지 업로드
2022, Oct 17
이미지 업로드하기
사전 설정
$ pip install Pillow
$ pip install pilkit
$ pip freeze > requirements.txt
- Pillow의 설치 이유 : 이미지를 관리하기 위해서(Python Image Library)
models.py
# 1. 모델 설계 (DB 스키마 설계)
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)
forms.py
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
# 이미지 필드 추가
fields = ['title', 'content', 'image']
views.py
def create(request):
if request.method == 'POST':
# request.FILES 추가
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article_form.save()
messages.success(request, '글 작성이 완료되었습니다.')
return redirect('articles:index')
else:
article_form = ArticleForm()
context = {
'article_form': article_form
}
return render(request, 'articles/form.html', context=context)
forms.html
{% extends 'base.html' %}
{% load django_bootstrap5 %}
{% block body %}
{% if request.resolver_match.url_name == 'create' %}
<h1> 글쓰기 </h1>
{% else %}
<h1> 수정하기 </h1>
{% endif %}
<!-- enctype 추가 -->
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form article_form %}
{% bootstrap_button button_type="submit" content="OK" %}
</form>
{% endblock %}
수정화면에서의 이미지 업로드
detail.html
{% extends 'base.html' %}
{% block body %}
<h1>{{ article.pk }}번 게시글</h1>
<p>{{ article.created_at|date:"SHORT_DATETIME_FORMAT" }} | {{ article.updated_at|date:"y-m-d D" }}</p>
<p>{{ article.content }} </p>
<img src="{{ article.image.url }}" alt="{{ article.image }}">
<a href="{% url 'articles:update' article.pk %}">수정하기</a>
{% endblock %}
settings.py
# Media files (user uploaded filed) 추가
MEDIA_ROOT = BASE_DIR / 'images'
MEDIA_URL = '/media/'
urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('articles/', include('articles.urls')),
path('accounts/', include('accounts.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
이미지 Resizing
terminal
$ pip install django-imagekit
models.py
# imagekit import
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)
# ProcessedImageField 추가
image = ProcessedImageField(upload_to='images/', blank=True,
processors=[ResizeToFill(400, 300)],
format='JPEG',
options={'quality': 80})
views.py
@login_required
def update(request, pk):
article = Article.objects.get(pk=pk)
if request.method == 'POST':
# POST : input 값 가져와서, 검증하고, DB에 저장
article_form = ArticleForm(request.POST, request.FILES, instance=article)
if article_form.is_valid():
# 유효성 검사 통과하면 저장하고, 상세보기 페이지로
article_form.save()
messages.success(request, '글이 수정되었습니다.')
return redirect('articles:detail', article.pk)
# 유효성 검사 통과하지 않으면 => context 부터해서 오류메시지 담긴 article_form을 랜더링
else:
# GET : Form을 제공
article_form = ArticleForm(instance=article)
context = {
'article_form': article_form
}
return render(request, 'articles/form.html', context)
detail.html
{% extends 'base.html' %}
{% block body %}
<h1>{{ article.pk }}번 게시글</h1>
<p>{{ article.created_at|date:"SHORT_DATETIME_FORMAT" }} | {{ article.updated_at|date:"y-m-d D" }}</p>
<p>{{ article.content }} </p>
{% if article.image %}
<img src="{{ article.image.url }}" alt="{{ article.image }}" width="400" height="300">
{% endif %}
<a href="{% url 'articles:update' article.pk %}">수정하기</a>
{% endblock %}
썸네일 업로드하기
models.py
from imagekit.models import ProcessedImageField
from imagekit.processors import Thumbnail
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': 60})
image_thumbnail = ProcessedImageField(
upload_to = 'images/', # settings.py 원본 ImageField 명
processors = [Thumbnail(100, 100)], # 처리할 작업목록
format = 'JPEG', # 최종 저장 포맷
options = {'quality': 60}) # 저장 옵션
forms.py
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
# 썸네일 추가
fields = ['title', 'content', 'image', 'image_thumbnail']
index.html
{% extends 'base.html' %}
{% load static %}
{% load django_bootstrap5 %}
{% block css %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
{% endblock %}
{% block body %}
<h1>게시판</h1>
{% if request.user.is_authenticated %}
<a class="btn btn-primary my-3 float-right" href="{% url 'articles:create' %}">글 쓰기</a>
{% endif %}
<div class="row">
{% for article in articles %}
<div class="col-4">
<div class="card">
# image_thumbnail로 변경
<img src="{{ article.image_thumbnail.url }}" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{ article.title }}</h5>
<a href="{% url 'articles:detail' article.pk %}" class="btn btn-outline-primary my-3">복습하기</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
detail.html
{% extends 'base.html' %}
{% block body %}
<h1>{{ article.pk }}번 게시글</h1>
<p>{{ article.created_at|date:"SHORT_DATETIME_FORMAT" }}
|
{{ article.updated_at|date:"y-m-d D" }}</p>
<p>{{ article.content }}
</p>
{% if article.image %}
<img src="{{ article.image.url }}" alt="{{ article.image }}" width="400" height="300">
{% endif %}
{% if article.image_thumbnail %}
<img src="{{ article.image_thumbnail.url }}" alt="{{ article.image_thumbnail }}" width="400" height="300">
{% endif %}
<a href="{% url 'articles:update' article.pk %}">수정하기</a>
<a href="{% url 'articles:delete' article.pk %}">삭제하기</a>
{% endblock %}