Django의 FileField를 기존 파일로 설정


90

디스크에 기존 파일 (예 : /folder/file.txt)과 Django에 FileField 모델 필드가 있습니다.

내가 할 때

instance.field = File(file('/folder/file.txt'))
instance.save()

파일을 file_1.txt(다음 번 _2에 등) 으로 다시 저장합니다 .

나는 그 이유를 이해하지만이 동작을 원하지 않습니다. 필드가 연결되기를 원하는 파일이 실제로 나를 기다리고 있다는 것을 알고 있으며 Django가이를 가리 키기를 원합니다.

어떻게?


1
Django 또는 하위 클래스를 수정하지 않고 원하는 것을 얻을 수 있는지 확실하지 않습니다 FileField. a FileField가 저장 될 때마다 파일의 새 사본이 생성됩니다. 이를 방지하는 옵션을 추가하는 것은 매우 간단합니다.
Michael Mior 2011

예, 하위 클래스를 만들고 매개 변수를 추가해야하는 것 같습니다. 나는이 간단한 작업을 위해 여분의 테이블을 만들고 싶지 않다
Guard

1
파일을 다른 위치에 넣고이 경로로 필드를 만들고 저장 한 다음 파일이 upload_to 대상에 있습니다.
benjaoming

답변:


22

이 작업을 영구적으로 수행하려면 고유 한 FileStorage 클래스를 만들어야합니다.

import os
from django.conf import settings
from django.core.files.storage import FileSystemStorage

class MyFileStorage(FileSystemStorage):

    # This method is actually defined in Storage
    def get_available_name(self, name):
        if self.exists(name):
            os.remove(os.path.join(settings.MEDIA_ROOT, name))
        return name # simply returns the name passed

이제 모델에서 수정 된 MyFileStorage를 사용합니다.

from mystuff.customs import MyFileStorage

mfs = MyFileStorage()

class SomeModel(model.Model):
   my_file = model.FileField(storage=mfs)

오, 유망 해 보인다. FileField의 코드는 다소 직관적이지 않습니다
Guard

하지만 ... 다음과 같이 요청별로 스토리지를 변경할 수 있습니까? instance.field.storage = mfs; instance.field.save (이름, 파일); 하지만 내 코드의 다른 지점에서하지 않습니다
Guard

2
아니요, 스토리지 엔진이 모델에 연결되어 있기 때문입니다. 파일 경로를 a FilePathField또는 단순히 일반 텍스트로 저장하여이 모든 것을 피할 수 있습니다 .
Burhan Khalid

이름 만 반환 할 수는 없습니다. 먼저 기존 파일을 제거해야합니다.
Alexander Shpindler

124

instance.field.name파일 경로로 설정 하십시오.

class Document(models.Model):
    file = FileField(upload_to=get_document_path)
    description = CharField(max_length=100)


doc = Document()
doc.file.name = 'path/to/file'  # must be relative to MEDIA_ROOT
doc.file
<FieldFile: path/to/file>

15
MEDIA_ROOT, 즉 의 상대 경로 입니다.
mgalgs nov.

7
이 예에서, 당신도 바로 할 수 있다고 생각doc.file = 'path/to/file'
앤드류 Swihart

13

이것을 시도하십시오 ( doc ) :

instance.field.name = <PATH RELATIVE TO MEDIA_ROOT> 
instance.save()

5

자신의 스토리지 클래스를 작성하는 것이 옳습니다. 그러나 get_available_name재정의하는 올바른 방법이 아닙니다.

get_available_nameDjango가 동일한 이름의 파일을보고 사용 가능한 새 파일 이름을 얻으려고 할 때 호출됩니다. 이름을 바꾸는 것은 방법이 아닙니다. 그 원인은_save . 의 주석은 _save꽤 좋으며 os.O_EXCL동일한 파일 이름이 이미 존재하면 OSError를 발생시키는 플래그로 작성하기 위해 파일을 쉽게 열 수 있습니다 . Django는이 오류를 포착 한 다음 호출 get_available_name하여 새 이름을 얻습니다.

그래서 올바른 방법은 _saveflag없이 os.open () 을 재정의 하고 호출하는 것 os.O_EXCL입니다. 수정은 아주 간단하지만 방법이 조금 길어서 여기에 붙여 넣지 않습니다. 도움이 더 필요하면 알려주세요. :)


복사해야하는 50 줄의 코드는 꽤 나쁩니다. get_available_name 재정의 더 짧은, 그리고 말하자면, 훨씬 더 안전하고, 미래에 장고의 최신 버전으로 업그레이드 격리 된 것 같다
마이클 Gendin

2
의 문제 만을 오버라이드 (override)는 get_available_name이 같은 이름의 파일을 업로드 할 때, 서버가 무한 루프에 들어갈 것입니다. 이후 _save및 검사 파일 이름 그러나 새로운 하나를 얻을하기로 결정 get_available_name여전히 중복 하나를 반환합니다. 따라서 둘 다 재정의해야합니다.
x1a0

1
아차, 우리는 두 가지 질문이 토론을하고,하지만 지금은 약간 다릅니다 것으로 나타났습니다) 나는 그 질문에 맞다 그래서, 당신이)에
마이클 Gendin

1

나는 똑같은 문제가 있었다! 그런 다음 내 모델이 그 원인을 알았습니다. 예를 들어 다음과 같은 모델을 사용했습니다.

class Tile(models.Model):
  image = models.ImageField()

그런 다음 디스크의 동일한 파일을 참조하는 하나의 타일을 더 많이 갖고 싶었습니다! 그것을 해결하기 위해 찾은 방법은 내 모델 구조를 다음과 같이 변경하는 것입니다.

class Tile(models.Model):
  image = models.ForeignKey(TileImage)

class TileImage(models.Model):
  image = models.ImageField()

같은 파일을 DB에 더 많이 저장하려면 다른 테이블을 만들어야하기 때문입니다.

모델을 변경할 수 있기를 바라면서도 그렇게 문제를 해결할 수 있다고 생각합니다!

편집하다

또한 다음과 같은 다른 저장소를 사용할 수 있다고 생각합니다. SymlinkOrCopyStorage

http://code.welldev.org/django-storages/src/11bef0c2a410/storages/backends/symlinkorcopy.py


내 경우가 아니라 귀하의 경우에 의미가 있습니다. 여러 번 참조되는 것을 원하지 않습니다. 파일을 참조하는 객체를 만든 다음 다른 속성에 오류가 있음을 깨닫고 생성 양식을 다시 엽니 다. 다시 제출할 때 디스크에 이미 저장된 파일을 잃고 싶지 않습니다
Guard

내 접근 방식을 사용할 수 있다고 생각합니다! 파일을 보관할 테이블 FormFile이 있기 때문입니다. 그런 다음 Form 테이블에 해당 파일에 대한 FK가 있습니다! 따라서 동일한 파일에 대해 새 양식을 변경 / 작성할 수 있습니다! (btw 나는 나의 주요 예에서 FK의 순서를 변경하고 있습니다)
Arthur Neves

게시물에 도메인 (모델)을 게시하려면! 나도 더 나은 아이디어를 가질 수 있습니다!
Arthur Neves 2011

도메인은 실제로 중요하지 않습니다. 관련 사진이있는 모델이 있고 사용자 지정 편집 화면이 있습니다. 일단 업로드되면 사진이 서버에 남아 있기를 원하지만 실제로는 프레임 워크 제한으로 보이기 때문에 별도의 모델, 테이블 및 FK 조회를 생성하는 것을 좋아하지 않습니다
Guard

여기서 제한은 Django에 FileField를 저장할 때 항상 Django Storage를 통과하기 때문이라고 생각합니다! 그래서 파일 경로를 강제하는 것은 의미가 없습니다! 또한 Django는 파일이 경로에 이미 존재한다는 것을 어떻게 알 수 있습니까? 사용할 수있는 또 다른 접근 방식은 대신 FilePathField를 사용하는 것입니다! 따라서 DB에 경로를 설정하고 최선이라고 생각하는 방식으로 조회 할 수 있습니다!
Arthur Neves 2011

1

자체 스토리지를 정의하고 FileSystemStorage에서 상속하고 OS_OPEN_FLAGS클래스 속성 및 get_available_name()메서드를 재정의해야 합니다 .

Django 버전 : 3.1

프로젝트 /core/files/storages/backends/local.py

import os

from django.core.files.storage import FileSystemStorage


class OverwriteStorage(FileSystemStorage):
    """
    FileSystemStorage subclass that allows overwrite the already existing
    files.
    
    Be careful using this class, as user-uploaded files will overwrite
    already existing files.
    """

    # The combination that don't makes os.open() raise OSError if the
    # file already exists before it's opened.
    OS_OPEN_FLAGS = os.O_WRONLY | os.O_TRUNC | os.O_CREAT | getattr(os, 'O_BINARY', 0)

    def get_available_name(self, name, max_length=None):
        """
        This method will be called before starting the save process.
        """
        return name

모델에서 사용자 지정 OverwriteStorage를 사용합니다.

myapp / models.py

from django.db import models

from core.files.storages.backends.local import OverwriteStorage


class MyModel(models.Model):
   my_file = models.FileField(storage=OverwriteStorage())
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.