일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- react
- 알고리즘
- java
- django rest framework
- js
- 파이썬 알고리즘
- web
- 알고리즘 연습
- HTML
- Git
- 파이썬
- API
- CSS
- DRF
- 알고리즘 풀이
- Django
- AWS
- javascript
- PYTHON
- Baekjoon
- c++
- 장고
- Algorithm
- es6
- form
- 백준
- django widget
- django ORM
- MAC
- 알고리즘 문제
- Today
- Total
수학과의 좌충우돌 프로그래밍
[Django] media 파일 업로드하기 본문
Media 파일이란?
media 파일이란 FileField 를 통해 저장한 모든 파일을 지칭합니다. 물론 ImageField 도 FileField 를 상속받은 필드로서 유사 필드들을 통해 저장된 파일도 media 파일입니다. 이는 특별하게 db 필드에는 저장경로를 저장하고 파일은 뒤에서 다시 다루겠지만 settings.MEDIA_ROOT
경로에 저장 하게 됩니다.
settings 에서의 설정
-
MEDIA_URL
MEDIA_URL = '/media/'
각 media 파일에 대한 URL 의 고정값을 설정할 수 있습니다. 예시를 들자면
필드명.url
에 의해 MEDIA 파일에 대하여 접근할 때 결정되는 값입니다. -
MEDIA_ROOT
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
FileField 를 통해서 저장 시 db 에는 파일의 경로가 문자열로 저장된다고 앞에서도 언급하였습니다. 그래서 실제 파일이 저장될 ROOT 경로를 설정합니다.
파일 업로드
위에 설정을 마쳤으니 파일 업로드 하는 과정을 알아보도록 합시다.
# models.py
class Profile(models.Model):
name = models.CharField(max_length=10)
photo = models.ImageField(upload_to="")
models 에 ImageField
을 추가해주고 이미지를 받을 수 있도록 했습니다. MEDIA_ROOT
를 지정해줌으로서 해당 경로에 이미지 사진을 저장하게 됩니다. 위의 예시 같은 경우에는 BASE_DIR/media
위치에 저장이 될 것이고 상황에 따라 스토리지 등에 저장을 할 수 있습니다. 그러면 한 폴더 내에 모든 파일이 전부 저장이 되는 것일까요? 모델 옵션을 통해서 이를 구체화 해줄 수 있습니다. 성능적인 부분으로 볼 때도, 한 디렉토리 내에 너무 많은 파일들이 저장되어 있다면 좋지 않습니다. 따라서 위 처럼 upload_to
옵션으로서 이를 지정해줄 수 있습니다.
makemigrations 시 오류가 뜬다면?
file 을 다루기 위해서는 파이썬 패키지인 pillow 가 필요합니다. 따라서 pillow 를 install 해주도록 합니다.
-
upload_to
두 가지 인자로 경로를 지정할 수 있습니다.
-
문자열
문자열로 지정할 경우, 중간 디렉토리 경로를 지정
# media/image/ 아래에 저장 photo = models.ImageField(upload_to="image") # 이미지 업로드 날짜에 따라 디렉토리에 저장 (strftime 으로 포멧팅) photo = models.ImageField(upload_to="%Y/%m/%d")
-
함수
함수로 지정할 경우, 중간 디렉토리 및 파일명까지 결정 가능
import os from uuid import uuid4 from django.utils import timezone def date_upload_to(instance, filename): # upload_to="%Y/%m/%d" 처럼 날짜로 세분화 ymd_path = timezone.now().strftime('%Y/%m/%d') # 길이 32 인 uuid 값 uuid_name = uuid4().hex # 확장자 추출 extension = os.path.splitext(filename)[-1].lower() # 결합 후 return return '/'.join([ ymd_path, uuid_name + extension, ]) photo = models.ImageField(upload_to=date_upload_to)
-
<!-- index.html -->
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<!-- 생략 -->
</form>
form
으로 부터 이미지를 입력을 받을 시에는 두 가지를 설정해주셔야 합니다. (csrf_token은 당연한 과정이므로 굳이 설명하지 않겠습니다.) method 는 POST로, enctype 도 다음과 같이 설정을 해주셔야 합니다. enctype 을 설정하지 않으신다면 파일은 넘어오지 않고 파일 이름만 넘어오게 됩니다.
# views.py
def create(request):
# 생략
profile.photo = request.FILES['photo']
파일을 받을 떄는 다음과 같이 request.FILES
로 받게 됩니다.
# config/urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
static 파일과 다르게 장고는 개발 서버에서 서빙을 지원해주지 않습니다. 쉽게 설명하면 지금 이런 과정을 해봤자 말짱 도루묵이라는 거죠. 다행히도 직접 서빙 rule를 추가할 수 있습니다. MEDIA_URL
에 대한 요청이 오면 MEDIA_ROOT
에서 찾게 됩니다. 다음 설정은 DEBUG
가 True 일 때만 동작하고 false 일 때는 빈 리스트를 return 합니다.
저장한 MEDIA 파일 사용
저장된 media 파일을 사용하기 위해서는 두 가지 속성을 알아야합니다. url
과 path
입니다.
<!-- 1번 -->
<img src="{{ profile.photo }}" >
<!-- 2번 -->
<img src="{{ profile.photo.url }}" >
<!-- 3번 -->
<img src="{{ profile.photo.path }}" >
3가지의 차이를 알아봅시다.
1번은 우리가 원하는 결과를 도출할 수 없습니다. 계속 말하지만 db에는 파일의 경로가 문자열로 저장되어 있기 때문에 저 부분은 그저 문자열을 참조할 뿐이죠.
2,3 번은 우리가 원하는 결과를 얻을 수 있습니다. 둘의 차이는 url
은 media 폴더 부터 시작하는 상대 경로를, path
는 절대경로를 나타냅니다. 뭐가 되었든 파일이 저장되어있는 media 파일을 참조하기 때문에 이미지를 불러올 수 있습니다.
해당 photo
가 존재하지 않는다면 이는 경로를 찾지 못해서 오류가 나기 때문에 다음과 같이 오류를 예방해주는 것도 좋은 방법입니다.
{% if profile.photo %}
<img src="{{ profile.photo.url }}" >
{% endif %}
'웹프로그래밍 > Django' 카테고리의 다른 글
[Django] CBV (2) Generic display views (2) | 2019.08.06 |
---|---|
[Django] CBV (1) CBV 와 Base Views (2) | 2019.08.06 |
[Django] static 파일 다루기 (0) | 2019.07.30 |
[Django] json_script 를 이용한 효과적인 json parsing (1) | 2019.07.28 |
[Django] django-debug-toolbar 설치하기 (0) | 2019.07.26 |