본문 바로가기

Framework/Django

[Django] Django Model Field - FileField (1)

반응형

1. FileField

FileField 파일 업로드를 위한 필드이다. FileField 두가지 선택 인자가 있는데 upload_to storage 이다.

- FileField.upload_to

파일 업로드 디렉토리와 파일 이름을 설정하는 속성으로 두가지 방법으로 설정할 있다. 두가지 방법 모두 설정한 값들이 Storage.save() 메서드로 전달된다.

 

만약 아래와 같이 strftime() 형식을 포함한 문자열 값이나 Path 객체로 값을 설정한 경우, 파일 업로드시의 날짜/시간으로 해당 형식이 대체된다.

 

class MyModel(models.Model):
	# 파일은 MEDIA_ROOT/uploads 경로에 저장된다.
	upload = models.FileField(upload_to="uploads/")

	# 파일은 MEDIA_ROOT/uploads/연도/월/날짜 형식의 디렉토리에 저장된다.
	upload = models.FileField(upload_to="uploads/%Y/%m/%d")

 

기본 FileSystemStorage 사용한다면, 파일 경로 값과 MEDIA_ROOT 경로가 합쳐진 경로에 로컬 파일 시스템에 파일이 저장된다. 다른 저장소를 사용하는 경우에는 해당 저장소에서 어떻게 upload_to 처리하는지 확인해야 한다.

 

upload_to 값은 함수와 같이 callable 객체도 있다. 함수는 파일명을 포함한 업로드 경로를 획득하기 위해 호출된다. callable 두개의 인자를 받아서 Unix-style 경로를 반환하도록 구현되야 한다.

 

두가지 인자는 각각 instance filename 으로 다음과 같다.

 

- instance: FileField 가 정의된 모델 객체로 현재 파일이 연결된 객체를 의미한다. 대부분의 경우 객체가 DB 에 저장되기 전 상태로 기본 AutoField 를 사용하는 경우 아직 PK 가 할당되기 전 상태이다.

- filename: 기본 파일에 지정된 파일명으로 파일의 최종 경로 지정시에 사용될 수도 있다.

 

upload_to callable 사용하는 경우의 예제는 다음과 같다.

 

def user_directory_path(instance, filename):
	# 파일은 MEDIA_ROOT/user_<id>/<filename> 경로에 저장된다.
	return "user_{0}/{1}".format(instance.user.id, filename)

class MyModel(models.Model):
	# upload_to 값으로 callable 인 user_directory_path 를 사용
	upload = models.FileField(upload_to=user_directory_path)

- FileField.storage

storage 객체 또는 storage 객체를 반환하는 callable 값으로 가진다. 파일의 저장과 검색을 처리한다.

- FileField

FileField 모델에서 사용하기 위해서는 아래와 같은 단계가 필요하다.

 

1) 설정 파일에서 MEDIA_ROOT 와 MEDIA_URL 을 설정한다. MEDIA_ROOT 는 장고가 업로드 된 파일을 저장할 경로로 디렉토리까지의 전체 경로를 지정한다. MEDIA_URL 은 저장 경로 디렉토리에 대한 기본 public URL 이다. 해당 디렉토리가 웹서버 사용자 계정으로 writable 한지 확인해야 한다.

2) 모델에 FileField 를 추가하고 upload_to 속성을 통해 MEDIA_ROOT 의 하위 경로를 지정하여 업로드 된 파일이 저장될 경로를 지정한다.

3) DB 에는 해당 파일에 대한 경로 (MEDIA_ROOT 로부터의 상대 경로) 가 저장된다. FileField 의 url 속성을 통해 이 경로를 가져올 수 있는데, 모델 객체에 file_location 이라는 FileField 컬럼이 있을때, {{ object.file_location.url }} 과 같은 문법으로 템플릿에서 파일에 대한 절대 경로를 획득할 수 있다.

 

MEDIA_ROOT "/home/media" 설정하고, upload_to "docs/%Y/%m/%d" 설정했다고 가정해보자. 경우에 upload_to "%Y/%m/%d" strftime() 형식으로 %Y 4자리 정수의 연도, %m 2자리 정수의 , %d 2자리 정수의 날짜로 매핑된다. 만약 2025 8 7일에 해당 필드에 파일을 업로드 했다면 파일은 /home/media/docs/2025/08/07 저장된다.

 

이외에도 파일에 대한 정보를 얻기 위해서 name 이나 size, url 같은 속성들을 사용할 있다. 이때 주의할 점은 파일의 저장은 해당 필드가 포함된 모델을 DB 저장하는 과정의 일부이기 때문에 디스크에서의 파일명 등은 모델 저장이 완료되기 전까지 확실하지 않을 있다.

 

업로드 파일을 다룰 때는 항상 어느 위치에 파일을 업로드하고 어떤 타입의 파일들인지를 신경써서 보안 문제를 피해야 한다. 업로드 되는 모든 파일을 검사해서 예상했던 파일들만 업로드 되도록 해야한다. 만약 이러한 검증이 없다면 CGI PHP 스크립트 등을 통해 해킹이나 잘못된 HTML 파일을 통한 XSS CSRF 공격일 발생할 있다.

 

FileField 객체는 DB varchar 컬럼으로 생성되며 기본값으로 문자 길이 100 으로 설정된다. 최대 길이는 max_length 인자로 변경할 있다.

2. FileField FieldFile

모델의 FileField 컬럼에 접근하면 컬럼에 연결된 파일에 접근하기 위한 프록시로 FieldFile 객체가 제공된다.

 

FieldFile API 장고의 File 객체 API 유사한데, 한가지 차이점이 있다. 클래스가 감싸고 있는 객체는 파이썬 built-in file 객체가 아닌 Storage.open() 메서드의 결과이다. 이는 File 객체일수도 있고 사용자 정의 storage File API 구현체일수도 있다.

 

FieldFile File 클래스에서 상속받은 read() write() API 외에도 내부 파일과 상호 작용하는 여러 기능들을 가지고 있다.

- FieldFile.name

파일의 이름을 나타내는 속성이다. FieldFile 과 연관된 FileField 의 Storage 의 루트로부터 상대경로를 포함하고 있다.

- FieldFile.path

read-only 속성으로 Storage 클래스의 path() 메서드를 호출하여 파일의 로컬 파일시스템 경로를 반환한다.

- FieldFile.size

내부 Storage.size() 메서드의 결과를 반환한다.

- FieldFile.url

read-only 속성으로 Storage 클래스의 url() 메서드를 호출하여 파일의 상대 URL 을 반환한다.

- FieldFile.open(mode='rb')

FieldFile 객체와 연결된 파일을 지정한 mode 로 여는 메서드이다. 파이썬의 표준 open() 메서드와 달리 file descriptor 를 반환하지 않는다.

 

만약 내부 파일에 접근하여 암시적으로 파일이 열린 경우, 파일에 대한 포인터를 리셋하거나 mode 를 변경하는 경우를 제외하고는 해당 메서드를 호출할 필요가 없다.

- FieldFile.close()

파이썬의 file.close() 와 동일하게 동작하여 해당 객체와 연결된 파일을 닫는다.

- FieldFile.save(name, content, save=True)

save() 메서드는 파일 이름과 파일 content 를 받아 해당 필드의 Storage 클래스로 전달한 뒤, 저장된 파일을 모델 필드에 연결한다. 모델에 있는 FileField 객체에 파일 데이터를 수동으로 연결하려고 한다면, save() 메서드를 사용해 파일 데이터를 영구적으로 저장할 수 있다.

 

save() 메서드는 두 개의 필수 인자를 받는다.

 

name: 저장할 파일 이름
content: 파일 내용을 담고 있는 객체

 

이 외에 save 라는 boolean 타입의 선택 인자를 가지고 있는데, 이 인자는 필드에 연결된 파일이 변경된 이후 모델 객체를 자동으로 저장할지 여부를 제어한다. 기본값은 True 이다.

 

주의할 점은 content 인자가 파이썬 built-in file 객체가 아닌 django.core.files.File 객체라는 것이다. 아래와 같은 방식으로 file 객체를 변환할 수 있다.

 

from django.core.files import File

# Open an existing file using Python's built-in open()
f = open("/path/to/hello.world")
myfile = File(f)


from django.core.files.base import ContentFile

myfile = ContentFile("hello world")

- FieldFile.delete(save=True)

 

이 객체와 연결된 파일을 삭제하고 필드의 모든 속성을 초기화한다. 이 메서드가 호출될 때 파일이 열려 있다면 파일을 닫는다.

 

delete() 메서드도 save() 메서드와 같이 선택 인자로 save 를 가지고 있는데, 이 필드에 연결된 파일이 삭제된 후 모델 객체를 저장할지 여부를 제어한다. 기본값은 True 이다.

 

주의할 점은 모델 객체가 삭제되어도 연결된 파일은 자동으로 삭제되지 않는다. 만약 이러한 orphan file 을 정리해야 한다면, 따로 처리하는 로직을 추가해야 한다.

[Reference]

- https://docs.djangoproject.com/en/5.2/ref/models/fields/#filefield

 

Model field reference | Django documentation

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

반응형