3.media 파일을 다루는 방법

1 분 소요

media 파일을 다루는 방법

Static & Media 파일

  • Static 파일
    • 개발 리소스로서의 정적 파일 (js, css, image 등)
    • 앱 / 프로젝트 단위로 저장/서빙
  • Media 파일 (django에만 존재하는 용어)
    • FileField / ImageField를 통해 저장한 모든 파일 (model field)
      • FileField : File Storage API를 통해 파일 저장(django는 File System Storage만 지원, django-storages를 통해 확장 지원)
      • ImageField : Pilow를 통해 이미지 width/height 획득
    • DB필드에는 저장경로를 저장하며, 파일은 파일 스토리지에 저장

      실제로 문자열을 저장하는 필드(중요)

    • 프로젝트 단위로 저장/서빙

Media 파일 처리 순서

  • HttpRequest.FILES를 통해 파일 전달
  • view 로직이나 form 로직을 통해 유효성 검사 수행
  • FileField / ImageFiel 필드에 경로(문자열)를 저장
  • settings.MEDIA_ROOT 경로에 파일 저장

기본 settings

  • MEDIA_URL: 어떤 URL을 통해 접근하는지 결정
  • MEDIA_ROOT: 실제 파일을 저장할 ROOT 경로(클라우드 기반 가능)
# .settings
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

개발환경에서의 media 파일 서빙

  • static 파일과 다르게, 장고 개발서버에서 서빙 미지원
  • 개발 편의성 목적으로 직접 서빙 Rule 추가 가능
# .urls
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog1.urls')),
    path('instagram/', include('instagram.urls')),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

admin 설정

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ['id', 'photo_tag', 'message', 'is_public', 'message_length', 'created_at', 'updated_at']
    list_display_links = ['message']
    list_filter = ['created_at', 'is_public']
    search_fields = ['message'] # 검색기능

    def photo_tag(self, post):
        if post.photo: # 장고 쉘에서 해당 파일이 없을 수도 있기 때문에 if문 처리
            return mark_safe(f'<img src="{post.photo.url}" style="width: 72px" />') # mark_safe로 감싸주지 않으면 사진을 노출시키지 않음
        return None

모델필드 예시

  • 파일 저장시 upload_to 함수를 호출하여 저장경로를 계산
  • 인자 유형
    • 문자열로 지정 : “중간 디렉토리 경로”로서 활용
    • 함수로 지정 : “중간 디렉토리 경로” 및 “파일명”까지 결정 가능
class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    message = models.TextField()
    photo = models.ImageField(blank=True, upload_to='instagram/post/%Y/%m/%d') # 1폴더에 파일이 몰리는 것을 방지 uload_to
    tag_set = models.ManyToManyField('Tag', blank=True)
    is_public = models.BooleanField(default=False, verbose_name='공개여부')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

uuid를 통한 파일명 정하기

# utils.py
import os
from uuid import uuid4
from django.utils import timezone

def uuid_name_upload_to(instance, filename):
    app_lebel = 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,
    ])

File Upload Handler

  • 기본적으로 파일크기 2.5MB 이하일 경우
    • 메모리에 담겨 전달
  • 파일크기가 2.5MB 초과일 경우
    • 디스크에 담겨 전달

관련설정 settings.FILE_UPLOAD_MAX_MEMORY_SIZE

댓글남기기