2011-11-30 12 views
62

既存のファイル(例:/folder/file.txt)とDjangoのFileFieldモデルフィールドがあります。DjangoのFileFieldを既存のファイルに設定する

私は

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

を行うと、それは(など、それは_2だ次回、)file_1.txtとしてファイルを再保存します。

私はなぜこの動作をしたくないのか理解しています。フィールドを関連付ける必要があるファイルを知っています。本当に待っています。ちょうどDjangoが指し示すようにしたいのです。

どのようにですか?

+1

ないあなたがDjangoに変更または 'FileField'をサブクラス化せずに、あなたが望む結果を得ることができることを確認。 'FileField'が保存されるたびに、ファイルの新しいコピーが作成されます。これを回避するオプションを追加するのはかなり簡単です。 –

+0

はい、サブクラス化してパラメータを追加する必要があります。私はこの単純なタスクのために余分なテーブルを作成することはしません。 – Guard

+0

ファイルを別の場所に置いて、このパスでフィールドを作成して保存してから、upload_to宛先にファイルを保存します。 – benjaoming

答えて

18

FileStorageクラス

from django.core.files.storage import FileSystemStorage 

class MyFileStorage(FileSystemStorage): 

    # This method is actually defined in Storage 
    def get_available_name(self, 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) 
+0

ああ、有望そうだ。 FileFieldのコードはちょっと直感的ではありません – Guard

+0

しかし、...要求ごとにストレージを変更することは可能ですか?instance.field.storage = mfs; instance.field.save(name、file);私のコードの別の枝でそれをしない – Guard

+2

いいえ、ストレージエンジンはモデルに結びついているからです。ファイルパスを 'FilePathField'か単純なプレーンテキストのどちらかに格納するだけで、すべてを避けることができます。 –

0

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

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

、私は、ディスク内の同じファイルを参照するより1枚のタイルを持っていると思いました!私はそれを解決することが分かっ方法はこれに私のモデルの構造を変更した:

私は同じファイルが必要な場合は、私のDBにもっとして1を保存しているので、それは、より多くの意味を成して実現した後、私が持っている
class Tile(models.Model): 
    image = models.ForeignKey(TileImage) 

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

それのために別のテーブルを作成してください!

私はあなたもあなたのモデルを変更することができます期待して、あなたの問題を解決することができると思います!

EDITまた、私はあなたが、たとえば次のように、異なるストレージを使用することができますね

:SymlinkOrCopyStorageあなたは永久にこれを実行したい場合は、あなたがあなた自身を作成する必要が

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

+0

は私の場合ではなく、あなたのケースでは理にかなっています。私はそれが複数回参照されることを望んでいません。私はファイルを参照するオブジェクトを作成し、他のattrsにエラーがあることを認識し、作成フォームを再度開きます。再投稿時には、すでにディスクに保存されているファイル – Guard

+0

を失いたくないので、私のアプローチを使うことができますね!あなたが持っているファイルだけを保持するテーブルFormFileがあるからです!あなたのFormテーブルにはそのファイルのためのFKがあります!同じファイルの新しいフォームを変更/作成することができます! (btw私の主な例でFKの順番を変更しています) –

+0

投稿にドメイン(モデル)を投稿したい場合は!私はあまりにも良いイデアを持つことができます! –

4

独自のストレージクラスを作成するのは正しいことです。しかし、get_available_nameは正しい方法ではありません。

get_available_name Djangoは同じ名前のファイルを見て、新しい使用可能なファイル名を取得しようとすると呼び出されます。名前の変更を引き起こす方法ではありません。メソッドは_saveです。 _saveのコメントはかなり良いですし、フラグos.O_EXCLで書かれたファイルを簡単に見つけることができ、同じファイル名がすでに存在する場合はOSErrorをスローします。 Djangoはこのエラーをキャッチし、get_available_nameを呼び出して新しい名前を取得します。

正しい方法は、_saveをオーバーライドし、フラグos.O_EXCLなしでos.open()を呼び出すことです。修正は非常に簡単ですが、メソッドが少し長くなるので、ここに貼り付けません。あなたはより多くの助けが必要な場合を教えてください:)

+0

それはあなたがコピーしなければならない50行のコードですが、これはかなり悪いことです。 get_available_nameのオーバーライドは、将来、より新しいバージョンのDjangoにアップグレードするために、より孤立した、より短く、もっと安全です。 –

+1

「get_available_name」をオーバーライドするだけの問題は、同じ名前のファイルをアップロードするときです。無限ループに入る。 '_save'はファイル名をチェックして新しいファイルを取得することを決定するので、' get_available_name'は依然として重複ファイルを返します。したがって、両方を無効にする必要があります。 – x1a0

+1

私たちは2つの質問でこのディスカッションをしていますが、今はちょっと違っていることに気がついたので)これは正しいと思います。 –

83

をちょうどあなたのファイルのパスに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> 
+11

あなたの 'MEDIA_ROOT'からの相対パスです。 – mgalgs

+6

この例では、 'doc.file = 'path/to/file''を実行することもできます –

7

doc)これを試してみてください。

instance.field.name = <PATH RELATIVE TO MEDIA_ROOT> 
instance.save() 
関連する問題