런타임시 upload_to가있는 Django FileField


130

사용자 joe가 파일을 업로드하면 모든 사람의 파일이 MEDIA_ROOT로 이동하는 대신 MEDIA_ROOT / joe로 이동하도록 업로드를 설정하려고합니다. 문제는 모델에서 이것을 정의하는 방법을 모른다는 것입니다. 현재 모습은 다음과 같습니다.

class Content(models.Model):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    file = models.FileField(upload_to='.')

그래서 내가 원하는 것은 '.'대신입니다. upload_to로 사용자 이름을 지정하십시오.

Django 1.0부터는 upload_to를 처리하기 위해 자신의 함수를 정의 할 수 있지만 그 함수는 사용자가 누구인지 알지 못하므로 조금 잃어 버렸습니다.

도와 주셔서 감사합니다!

답변:


256

아마도 documentation을 읽었을 것이므로 이해하기 쉬운 예제가 있습니다.

def content_file_name(instance, filename):
    return '/'.join(['content', instance.user.username, filename])

class Content(models.Model):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    file = models.FileField(upload_to=content_file_name)

보시다시피, 주어진 파일 이름을 사용할 필요조차 없습니다. 원한다면 upload_to 호출 가능 파일에서도 파일 이름을 무시할 수 있습니다.


네, 아마도 문서에 속할 것입니다-그것은 IRC에 대한 합리적인 FAQ입니다
SmileyChris

2
이것이 ModelForm과 함께 작동합니까? 인스턴스에 클래스 모델의 모든 속성이 있지만 값이 없습니다 (필드 이름의 str). 템플릿에서 사용자는 숨겨져 있습니다. 질문을 제출해야 할 수도 있습니다. 몇 시간 동안 인터넷 검색을 해왔습니다.
mgag

3
이상하게도 이것은 기본적 으로이 동일한 설정에서 나에게 실패합니다. instance.user에는 속성이 없습니다.
Bob Spryn

11
유닉스가 아닌 시스템에서도 작동하는지 확인 하는 os.path.join대신 사용할 수 있습니다 '/'.join. 드문 일이지만 좋은 습관입니다.)
Xudonax

2
안녕하세요, 같은 코드를 시도해 models.py에 넣었지만 오류가 발생합니다. Content 객체에는 'user'속성이 없습니다.
Harry

12

정말 도움이되었습니다. 좀 더 간결하게하기 위해 필자의 경우 람다를 사용하기로 결정했습니다.

file = models.FileField(
    upload_to=lambda instance, filename: '/'.join(['mymodel', str(instance.pk), filename]),
)

4
Django 1.7에서는 마이그레이션을 사용하여 작동하지 않았습니다. 대신 함수 작성이 끝나고 마이그레이션이 수행되었습니다.
aboutaaron

str (instance.pk)를 사용하여 람다를 작동시킬 수없는 경우에도 원하지 않는 파일 덮어 쓰기에 문제가있는 경우 좋은 아이디어입니다.
Joseph Dattilo

2
인스턴스에 pk저장하기 전에는 없습니다 . 생성 (삽입)이 아닌 업데이트에만 작동합니다.
모하마드 Jafar Mashhadi

람다는 문서migrations 에 따라 직렬화 할 수 없기 때문에 운영 에서 작동 하지 않습니다
Ebrahim Karimi

4

'인스턴스'객체의 pk 값 사용에 대한 참고 사항입니다. 설명서에 따르면 :

대부분의 경우이 개체는 아직 데이터베이스에 저장되지 않았으므로 기본 AutoField를 사용하는 경우 기본 키 필드 값이 아직 없을 수 있습니다.

따라서 pk 사용의 유효성은 특정 모델이 정의 된 방법에 따라 다릅니다.


값으로 None을 얻었습니다. 나는 그것을 고치는 방법을 알 수 없다. 조금 자세히 설명해 주시겠습니까?
Aman Deep

1

마이그레이션에 문제가있는 경우 @deconstructible데코레이터를 사용해야합니다 .

import datetime
import os
import unicodedata

from django.core.files.storage import default_storage
from django.utils.deconstruct import deconstructible
from django.utils.encoding import force_text, force_str


@deconstructible
class UploadToPath(object):
    def __init__(self, upload_to):
        self.upload_to = upload_to

    def __call__(self, instance, filename):
        return self.generate_filename(filename)

    def get_directory_name(self):
        return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to))))

    def get_filename(self, filename):
        filename = default_storage.get_valid_name(os.path.basename(filename))
        filename = force_text(filename)
        filename = unicodedata.normalize('NFKD', filename).encode('ascii', 'ignore').decode('ascii')
        return os.path.normpath(filename)

    def generate_filename(self, filename):
        return os.path.join(self.get_directory_name(), self.get_filename(filename))

용법:

class MyModel(models.Model):
    file = models.FileField(upload_to=UploadToPath('files/%Y/%m/%d'), max_length=255)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.