목표
- 사용자가 이미지를 업로드할 수 있는 기능을 구현한다.
- 미디어 파일에 대해서 이해한다.
Media file
static 컨텐츠에는 두 가지 종류가 있다.
1) static file
- 개발자가 웹 애플리케이션 개발을 위해 개발 과정에서 저장한 파일(css, javascript, image)
2) media file
- 사용자가 웹 애플리케이션에 업로드한 파일(image)
저번 포스트에서 static file을 관리하는 방법을 알아보았으니,
이번에는 media file을 업로드하고 관리하는 방법을 알아보자
Media files 저장 및 전달 설정
media file을 저장하고 관리할 수 있는 디렉터리 설정과 url 전달 설정이 필요하다.
settings.py에 아래의 코드를 추가한다.
# 미디어 파일을 관리할 루트 media 디렉터리
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 각 media file에 대한 URL prefix
MEDIA_URL = '/media/'
urls.py에 아래의 코드를 추가한다.
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
터미널에 아래 명령어 입력을 통해 pillow를 다운로드한다.
$ pip3 install pillow
pillow는 python3에서 이미지를 관리할 수 있는 패키지 이다.
Model 설정
이미지를 업로드하기 위한 Djagno 프로젝트 자체에 대한 설정은 끝났다.
이제 이미지를 업로드할 수 있도록 모델에 속성을 추가해주어야한다.
이미지는 테이블 속성 값으로 이미지 자체로 저장되어있는 것이 아닌 '/media/이미지이름.png' 처럼 path가 저장된다.
만약 게시글마다 이미지를 하나만 올릴 수 있다고 한다면 테이블을 아래처럼 구성될 것이고,
Model에서 클래스에 아래처럼 'ImageFiled' 하나만 추가해주면 된다.
class Post(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
content = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
image = models.ImageField(upload_to='images/',blank=True, null=True)
def __str__(self):
return self.title
하지만, 게시글에 여러 개의 이미지를 저장하고 볼 수 있으려면 게시글과 이미지가 1:n 관계를 맺을 수 있도록 모델을 구성해주어야한다.
따라서 model에 Photo라는 새로운 클래스를 하나 만들고 Post와 1:n의 관계를 맺도록 ForeignKey 필드를 사용해 Post 테이블을 참조하도록 한다.
class Post(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
content = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
def __str__(self):
return self.title
class Photo(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, null=True)
image = models.ImageField(upload_to='images/', blank=True, null=True)
model에 대한 수정이 끝났다면 migration을 해준다.
admin 설정
admin 페이지에서 Photo 테이블을 볼 수 있도록 설정해보자.
이전의 Post와는 다른 설정을 해야한다.
Photo라는 테이블이 개별로 존재하는 것으로 나타내는 것이아닌,
Post 테이블의 각 레코드 안에 해당하는 Photo의 레코드를 나타내주어야하기 때문이다.
admin.py를 아래와 같이 수정해준다.
from django.contrib import admin
from .models import Post, Photo
# Photo 클래스를 inline으로 나타낸다.
class PhotoInline(admin.TabularInline):
model = Photo
# Post 클래스는 해당하는 Photo 객체를 리스트로 관리하는 한다.
class PostAdmin(admin.ModelAdmin):
inlines = [PhotoInline, ]
# Register your models here.
admin.site.register(Post, PostAdmin)
이제 admin 페이지에서 Post의 레코드 내에서 해당 Photo를 삽입/갱신/삭제가 가능하다.
! 일치하는 속성 값이 없다는 에러가 뜨는 경우
이미지 캡쳐본을 찍지 못했다.
컬럼을 추가하면서 이전에 존재하던 레코드에 해당하는 컬럼 값이 존재하지 않는다는 에러가 뜨는 경우
migation할 때,
$ python3 manange.py migrate --run-syncdb
를 통해 동기화 시켜주자.
Form
템플릿에서 이미지를 업로드할 수 있도록 form을 수정한다.
<form method="POST" action="{% url 'create' %}" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="title">
<input type="text" name="content">
<input type="file" name="imgs" multiple>
<input type="submit" value="작성하기">
</form>
form 태그에 enctype="multipart/form-data" 속성을 추가하고,
이미지 파일을 여러개 입력 받을 수 있도록 '<input type="file" name="imgs" multiple>' 태그를 추가한다.
View
views.py를 아래처럼 수정한다.
from .models import Post, Photo
...
def create(request):
if(request.method == 'POST'):
post = Post()
post.title = request.POST['title']
post.content = request.POST['content']
post.pub_date = timezone.datetime.now()
post.user = request.user
post.save()
# name 속성이 imgs인 input 태그로부터 받은 파일들을 반복문을 통해 하나씩 가져온다
for img in request.FILES.getlist('imgs'):
# Photo 객체를 하나 생성한다.
photo = Photo()
# 외래키로 현재 생성한 Post의 기본키를 참조한다.
photo.post = post
# imgs로부터 가져온 이미지 파일 하나를 저장한다.
photo.image = img
# 데이터베이스에 저장
photo.save()
return redirect('/detail/' + str(post.id))
else:
return render(request, 'new.html')
Post를 생성하도록 처리된 create 메소드 안에서 전달된 이미지를 반복문으로 하나씩 저장한다.
template
detail.html에 아래와 같은 코드를 작성해준다.
{% for photo in post.photo_set.all%}
<img src="{{photo.image.url}}" width="50"><br>
{% endfor %}
저장할 때와 마찬가지로 반복문을 통해 해당 Post에 저장된 이미지를 하나씩 출력한다.
이미지가 잘 추가되는 것을 확인할 수 있다.
'Web Programming > django' 카테고리의 다른 글
[Django] 부트스트랩 (0) | 2020.06.22 |
---|---|
[Django] URL 관리 (0) | 2020.06.22 |
[Django] 정적파일 (1) | 2020.06.21 |
[Django] 모델 관계 (2) (0) | 2020.06.21 |
[Django] 모델 관계 (1) (0) | 2020.06.21 |
댓글