web-dev-qa-db-ja.com

DjangoのFileFieldを既存のファイルに設定します

ディスクに既存のファイル(たとえば/folder/file.txt)とDjangoのFileFieldモデルフィールドがあります。

私がする時

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

ファイルをfile_1.txtとして保存し直します(次回は_2など)。

理由はわかりますが、この動作は望ましくありません。フィールドに関連付けたいファイルが実際にそこにあることを知っており、Djangoがそれを指すようにするだけです。

どうやって?

78
Guard

これを永続的に行いたい場合は、独自の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)
19
Burhan Khalid

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>
99
bara

これを試してください( doc ):

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

独自のストレージクラスを記述するのは正しいことです。ただし、get_available_nameはオーバーライドする正しい方法ではありません。

get_available_nameは、Djangoが同じ名前のファイルを検出し、使用可能な新しいファイル名を取得しようとしたときに呼び出されます。名前を変更するのはメソッドではありません。原因となったメソッドは_saveです。 _saveのコメントは非常に優れており、同じファイル名が既に存在する場合にOSErrorをスローするフラグos.O_EXCLを使用して書き込み用にファイルを開くことが簡単にわかります。 Djangoはこのエラーをキャッチし、get_available_nameを呼び出して新しい名前を取得します。

正しい方法は、_saveをオーバーライドし、フラグos.O_EXCLなしでos.open()を呼び出すことだと思います。変更は非常に簡単ですが、方法は少し長いので、ここに貼り付けません。さらにヘルプが必要な場合は教えてください:)

5
x1a0

私はまったく同じ問題を抱えていました!私のモデルがそれを引き起こしていることに気付きます。例:私は次のようにモデルを作成しました:

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

次に、ディスク内の同じファイルを参照する1つ以上のタイルが必要でした!それを解決するために私が見つけた方法は、私のモデル構造をこれに変更しました:

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

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

私がそれを理解した後、同じファイルをDBに保存したい場合は別のテーブルを作成する必要があるため、それはより理にかなっています!

モデルを変更できることを期待して、そのような問題も解決できると思います!

[〜#〜] edit [〜#〜]

また、たとえば次のような別のストレージを使用できると思います:SymlinkOrCopyStorage

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

0
Arthur Neves