TIL114. Django : Media File 다루기

ID짱재·2022년 1월 19일
1

Django

목록 보기
42/43
post-thumbnail

📌 이 포스팅에서는 Django에서 Media File를 다루는 settings 방법에 대해 정리하였습니다.


🌈 Media File 다루기

🔥 settings.py 설정

🔥 urls.py 설정

🔥 ImageField 설정

🔥 admin 설정


1. settings.py 설정

🤔 settings.py 설정이란?

✔️ image 파일 등 media 파일을 다룰 수 있도록 저장 경로와 접근 경로(url)을 설정하는 기능을 django에서제공한다.

✔️ S3등을 이용하여 외부 경로에 저장할 경우, 접근 경로인 url을 DB에 저장시켜도 되지만, 내부적으로 파일을 저장하고 그 경로를 지정하기 위한 조치가 settings.py에서 이뤄진다.

✔️ 맨 처음엔 아래처럼 STATIC_URL만 경로가 잡혀있고, 이는 정적 파일에 대한 경로이다.

STATIC_URL = 'static/'

✔️ media 파일을 다루기 위해 MEDIA_URL과 MOEDIA_ROOT를 직접 지정해야 한다.

STATIC_URL = 'static/'
MEDIA_URL = '/media/' # 👈 /media로 파일에 접근하기 위한 최상위 URL을 지정
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 👈 실제 파일이 저장되는 경로를 지정

✔️ 만일 프로젝트 내 최상위 경로(BASE_DIR) 밖에 파일을 저장시키고 싶다면 아래 처럼도 지정할 수 있다. 프로젝트 최상위 경로 바로 밖에 public이라는 디렉토리를 만ㄷㄹ고, media라는 디렉토리 내에 저장시키겠다는 의미이다.

STATIC_URL = 'static/'
MEDIA_URL = '/media/' 
MEDIA_ROOT = os.path.join(BASE_DIR, '..', 'public', 'media') # 👈 root 밖에 public/media에 이미지가 저장

2. urls.py 설정

🤔 urls.py에

✔️ settings.py의 설정이 끝났다면, urls.py에서 경로를 지정해주어야 한다.

✔️ 여기서 static 파일의 경로를 지정하지 않으면, 실제 이미지 파일의 url로 접근해도 해당 이미지를 확인할 수 없다.

✔️ 마치, view를 작성했는데 urls.py에 url과 매핑을 하지 않은 것과 같다.

✔️ DEBUG=True일 경우만이라고 명시하지만, 사실 조건이 없다해도(DEBUG=False일 때) url 리스트를 빈배열을 반환하기 때문에 기능상으론 같다. 다만, 명시적으로 표시하기 위해 일반적으로 이렇게 쓴다.

from django.conf.urls.static import static # 👈 static 경로를 지정하기 위해 static import
from django.conf import settings # 👈 conf의 settings를 import
from django.contrib import admin
from django.urls import path, include
# 최상위 urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
]
# static 파일 경로 설정
if settings.DEBUG: # 👈 DEBUG=True일 때만,
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

🤔 django settgins를 사용할 때,, 파일로 직접 접근하지 않는 이유

✔️ django에서 settings에 접근하여 값을 불러올 때, 직접 접근하지 않고 아래 처럼 사용한다.

✔️ 그 이유는, global_settings에 우리 프로젝트 내 settings.py를 오버라이드해서 사용하기 때문에 아래와 같이 import한다.

from django.conf import settings

✔️ 쉽게말해, 아래 2가지를 합친게 from django.conf import settings와 같은 것이다.

from django.conf import global_settings
from core import settings

3. ImageField 설정

🤔 파일의 종류별 지원하는 패키지

✔️ FileField를 사용하여 File을 저장하는 경우에는 django-storages를 설치하여 사용한다.

$ pip install django-storages

✔️ image 파일이라면, ImageField를 사용하고 Pillow를 설치한다.

$ pip install pillow

🤔 테이블의 image를 저장하는 필드는 ImageField이다.

✔️ photo라는 column에 이미지 경로를 저장하기 위해, ImageField를 사용했고, upload_to를 해당 이미지가 저장될 때, 이 이미지를 하위 디렉토리를 설정해주기 위한 기능이다.

from django.db import models
from core.models import TimeStampModel
# Post 테이블
class Post(TimeStampModel):
    message = models.TextField()
    photo = models.ImageField(blank=True, upload_to='instagram/post/%Y/%m/%d')
    is_public = models.BooleanField(default=False, verbose_name='공개여부')

🤔 upload_to 옵션에 관한여

✔️ settings에서 BASE_DIR의 media 디렉토리에 이미지를 저장하기로 지정하였는데, upload_to를 지정하지 않으면 여러 테이블에서 지정된 이미지들이 잘 정돈되지 않는다.

STATIC_URL = 'static/'
MEDIA_URL = '/media/' # 👈 /media로 파일에 접근하기 위한 최상위 URL을 지정
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 👈 실제 파일이 저장되는 경로를 지정

✔️ 어떤 테이블의 column에서 저장했는지 디렉토리의 depth를 만들어주기 위해 upload_to 옵션을 사용할 수 있다.

✔️ 위에 처럼 ImageField 내에 정할 경우, BASE_DIE/media/instagram/post/년/월/일 디렉토리 아래에 저장된다.

✔️ 아래처럼 upload_to 기능을 오버라이딩하여하여 사용할 수도 있다.

import os
from uuid import uuid4
from django.utils import timezone
# upload_to 커스텀
def uuid_name_upload_to(instance, filename):
    app_label = instance.__class__._meta.app_label # 👈 앱 별로
    cls_name = instance.__class__.__name__.lower() # 👈 모델 별로
    ymd_path = timezone.now().strftime('%Y/%m/%d') # 👈 년/월/일 별로
    uuid_name = uuid4().hex
    extension = os.path.splitext(filename)[-1].lower() # 👈 확장자 추출하고, 소문자로 변환
    return '/'.join(
        app_label,
        cls_name,
        ymd_path,
        uuid_name[:2],
        uuid_name + extension,
    )

4. admin 설정

🤔 mark_safe를 통해 admin에 이미지 노출시키기

✔️ photo_tag라는 이미지의 url 경로를 반환하는 함수를 만들어 list_display에 넣으면, admin 페이지에서 이미지를 확인할 수 있다.

✔️ mark_safe는 django의 보안 기능으로 태그를 바로 노출시키지 않고 string으로 변환하기 때문에 안전한 태그라는 것을 django에게 알려주기 위한 기능이다.

from django.contrib import admin
from django.utils.safestring import mark_safe
from .models import Post
# Post Admin Custom
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ['id', 'message', 'message_length', 'is_public', 'photo_tag', 'created_at', 'updated_at']
    list_display_links = ['message']
    list_filter = ['created_at', 'is_public']
    search_fields = ['message']
    # admin 페이지에서 이미지 바로 확인하는 방법
    def photo_tag(self, post):
        if post.photo: # 👈 photo url이 있다면,
            return mark_safe(f'<img src="{post.photo.url}" style="width:72px"/>')
        return None

profile
Keep Going, Keep Coding!

0개의 댓글