django에서 파일 또는 이미지 업로드 기능을 사용하려면 장고 모델의 ImageField, FileField에서 사용하는 upload_to
를 설정해야 합니다.
upload_to
에 설정한 값은 DEFAULT_FILE_STORAGE에 설정된 Storage 클래스에 있는 save() 메소드로 전달되어 파일을 저장할 때 사용됩니다.
upload_to에 값을 설정하기 전, settings.py에 정의되어야 하는 몇 가지 값이 있습니다.
MEDIA_URL = "/media/" #맨 앞에 /를 사용하여 절대경로로 지정
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
urlpatterns = [
path("admin/", admin.site.urls),
path("makers", include("makers.urls")),
path("users", include("users.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
upload_to argument는 두가지 방법으로 설정이 가능하여, 상황에 맞게 사용하면 됩니다.
class MyModel(models.Model):
upload = models.FileField(upload_to='uploads/')
upload_with_date = models.FileField(upload_to='uploads/%Y/%m/%d/')
첫번째는, upload_to에 string 값을 설정하는 방법입니다. 이 방법을 사용하면, 업로드하는 파일은 {MEDIA_ROOT}/{upload_to}/{업로드 하는 파일명}의 형태로 저장됩니다.
또한, datetime 모듈을 import하지 않고 %Y%m%d의 형태로 날짜 또는 시간을 입력할 수 있습니다. 이렇게 저장되는 이유는 위에 간단하게 말씀드렸다시피 upload_to의 값이 Storage 클래스로 전달된 후 Storage 클래스가 string을 처리하기 때문입니다.
def user_directory_path(instance, filename):
return 'user_{}/{}'.format(instance.name, filename)
class MyModel(models.Model):
name = models.CharField(max_length=20, blank=True, null=True)
upload = models.FileField(upload_to=user_directory_path)
두번째는, callable을 설정하는 방법인데, 메소드를 정의한 후에 그 메소드를 설정하는 방법입니다. 이 방법을 사용하면 uuid, random, datetime 모듈 등을 활용하여 업로드하는 파일의 경로와 파일명의 customizing을 간편하게 할 수 있습니다.
upload_to를 설정하는 두가지 방법을 알아보았는데, callable이 좋은 이유는 파일이 저장되는 경로를 변경하는 경우에 데이터베이스 migration이 필요하지 않다는 점입니다. 모델 필드에 직접 string값을 입력하게되면, upload_to값을 변경할 때마다 migration을 해야하지만, callable방식을 사용하면 코드가 수정되었을 때 migration을 하지 않아도 수정된 경로가 반영됩니다.
media 파일은 request.FILES로 받아줍니다. 아래는 프로필 사진을 업로드하는 저의 코드입니다.
"profile"의 값으로 사진을 업로드 하면 /media/profile 폴더 안에 저장되는 방식입니다.
if request.FILES["profile"]:
uploaded_profile = request.FILES["profile"]
fs = FileSystemStorage(
location="media/profile", base_url="/media/profile"
)
filename = fs.save(uploaded_profile.name, uploaded_profile)
uploaded_profile_url = fs.url(filename)
Django의 Storage 클래스
장고는 파일을 다루기 위해 Storage라는 클래스를 제공합니다. Storage 클래스는 파일을 다루는데 필요한 기본적인 메소드들을 가지고 있으며, 다른 파일 저장 시스템 클래스들은 이 클래스를 상속받아 만들어집니다.
Storage클래스가 가지는 기본적인 메소드들에는 open, save, delete, path, exists 등등이 있고, 이들 중 대부분의 메소드는 Storage를 상속받는 서브 클래스에서 반드시 정의해주어야하도록 되어있습니다. 장고에서 기본적으로 사용하는 파일 저장 시스템은 FileSystemStorage 클래스이며 Storage 클래스를 상속받는 이 클래스는 로컬 저장소에 파일을 저장하는 기본적인 파일 저장 시스템 기능을 가지고 있습니다.
우리가 지금까지 파일을 저장할 경로로 지정해주었던 MEDIA_ROOT 변수와 저장한 파일을 요청할 때 사용했던 MEDIA_URL 변수는 모두 FileSystemStorage 클래스에서 사용하는 변수로, 앞서 settings에서 지정해준 값으로 파일이 저장됩니다.
또한 FileSystemStorage는location
과base_url
속성을 가지고 있는데location
은 파일의 저장 경로를,base_url
은 url을 지정해줄 수 있습니다.
- FileSystemStorage 는 로컬 저장소에 파일을 저장하는 저장 시스템으로 실제 운영되는 서비스의 경우 프로젝트와 같은 공간에 미디어 파일들을 저장한다면 저장 용량, 보안, 백업 등 여러가지 문제가 생길 수 있습니다. 따라서 미디어 파일들을 관리하는데 특화된 별도의 저장소를 구축하여 운영하는 것이 좋으며, 그러한 별도의 저장소 서비스 중 하나가 Amazon S3입니다.
- media/profile에 저장된 모습
이미지 업로드를 test하기 위해서는 아래의 화면과 같이 Body의 form-data를 통해서 값을 전달해야 합니다. key 값에 FILES['key']에 해당하는 값을 넣고, 오른쪽의 탭에서 text가 아닌 file로 설정하여 업로드하고 싶은 파일을 value값에 지정합니다. 이렇게 하여 이미지 파일은 전송하고, data를 포함하여 같이 전송하는 경우에는 request.body가 아닌 request.POST['data']와 같은 방식으로 하여야 합니다. 아래의 사진과 같이 postman에서 data를 전송하고 data = json.loads(request.POST["data"])
와 같이 값을 받아 각 항목별로 나누어주면 됩니다!!
[이미지 파일]
[data 포함]
참고자료:http://johnnykims.blogspot.com/2016/05/django-imagefield-uploadto.html
감사합니다.