Form 강의에 이어서 Form 으로 파일을 업로드하려 한다

파일 업로드

설정

파일을 업로드 하기 위해선 먼저 업로드 할 장소를 설정해야 한다

Django 에서는 업로드 설정을 MEDIA_ROOT 로 정의되어 있다

settings.py

...
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')

BASE_DIR 은 settings.py에 설정되어 있다(root 경로와 같다)

나는 root 경로에 uploads 란 파일에 업로드 하겠다

업로드

models.py

class Pet(models.Model):
    def __str__(self):
        return self.pet_name
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    pet_name = models.CharField(max_length=50)
    thumbnail = models.ImageField(blank=True, null=True)

Pet 모델에 프로필 사진을 담을 thumbnail 을 ImageField로 선언하였다

ImageField 대신 FileField를 써도 되지만 유효성 검사를 위해 ImageField를 사용한다. blank 는 해당 속성이 비어도 되는지 나타내는 것이고 null은 말그대로 null이 들어가도 되는지 나타내는 것이다. 어떤 조건이든 비어도 가능하게 설정하려면 둘다 True 로 하면 된다

upload_to 인자를 함께 넣어 경로를 따로 지정할 수 있다
(하지만 MEDIA_ROOT 경로와 합쳐지더라....)

forms.py

from django import forms

from .models import Pet


class PetFormModel(forms.ModelForm):
    class Meta:
        model = Pet
        fields = ['thumbnail', 'pet_name', 'pet_likes', 'pet_charming']

이전 강의에 사용하던 Form에 thumbnail Field 만 추가하였다

views.py

def registerPet(request):
    pet = Pet(owner=request.user)
    form = PetFormModel(request.POST, request.FILES, instance=pet)
        if form.is_valid():
            form.save()
        else:
            # 유효성 검사 실패
            redirect('/fail/') 
        return redirect('/success/')

간단히 request.FILES 만 Form으로 넣어주면 파일을 업로드 시킬 수 있다

업로드 된 파일 불러오기

MEDIA_ROOT 는 파일을 업로드할 장소를 뜻한다면,
MEDIA_URL 은 MEDIA_ROOT에 접근할 URL을 뜻한다

settings.py

MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
MEDIA_URL = '/uploads/'

그리고 MEDIA_URL을 활성화 시켜주자

urls.py

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
  ...
]

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

MEDIA_URL 을 활성화 시켜줬다면 http://localhost:8000/upload/FILE_NAME 과 같은 URL로 파일을 불러올 수 있다

업로드된 파일 삭제

models.py

class Pet(models.Model):
    def __str__(self):
        return self.pet_name
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    pet_name = models.CharField(max_length=50)
    thumbnail = models.ImageField(blank=True, null=True)

Pet의 thumbnail 속성은 이미지 파일 자체를 담는 것이 아니라 정보만 담고 있어서 Pet 객체가 지워져도 파일 자체는 지워지지 않는다

Trash 파일을 안남기기 위해 객체와 함께 파일 삭제하려면, 현재 Pet 모델에 delete 함수를 오버라이딩(재정의) 하자

models.py

class Pet(models.Model):
    def __str__(self):
        return self.pet_name
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    pet_name = models.CharField(max_length=50)
    pet_likes = models.CharField(max_length=200, default='')
    pet_charming = models.CharField(max_length=200, default='')
    thumbnail = models.ImageField(blank=True, null=True)
    # delete 오버라이딩
    def delete(self, *args, **kargs):
        os.remove(os.path.join(settings.MEDIA_ROOT, self.thumbnail.path))
        super(Pet, self).delete(*args, **kargs) # 원래의 delete 함수를 실행

이제 파일이 Pet 객체 인스턴스와 함께 삭제될 것이다