런타임시 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.