2011-11-30 22 views
62

我在Django的磁盤上存在一個存在的文件(比如/folder/file.txt)和一個FileField模型字段。將Django的FileField設置爲現有文件

當我做

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

它重新將文件保存爲file_1.txt(下一次它的_2等)。

我明白爲什麼,但我不想要這種行爲 - 我知道我想讓該字段關聯的文件真的在等待我,我只是想讓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

哦,看起來很有前途。 cuase FileField的代碼有點不直觀 – Guard

+0

但是...有可能在每個請求的基礎上更改存儲,如:instance.field.storage = mfs; instance.field.save(name,file);但不是在我的代碼的不同分支中執行它 – Guard

+2

不,因爲存儲引擎與模型綁定。您可以通過簡單地將文件路徑存儲在「FilePathField」中或簡單地作爲純文本來避免所有這些。 –

0

我有完全相同的問題!然後我意識到我的模型正在造成這種情況。例如,我哈得我的模型是這樣的:

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

然後,我想有更多的一個區塊引用在磁盤同一個文件!我發現要解決的辦法是改變我的模型結構,以這樣的:

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

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

後,我意識到,更有意義,因爲如果我想在同一個文件在我的數據庫被保存更多然後我有哪家爲它創建另一個表!

我想你也可以解決你的問題,只是希望你能改變模型!

編輯

此外,我想你可以使用不同的存儲,這樣的實例:SymlinkOrCopyStorage

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

+0

在你的情況下是合理的,而不是在我的情況下。我不希望它被多次引用。我創建了一個引用文件的對象,然後我意識到其他attrs中存在錯誤,並且我重新打開了創建表單。在它的重新提交中,我不想丟失已經保存在磁盤 – Guard

+0

上的文件,所以我想你可以使用我的方法!因爲你將有一個表格FormFile,它將保存文件只有你有!那麼在你的Form表格中,你將擁有該文件的FK!所以你可以爲同一個文件改變/創建新的表單! (順便說一句,我改變我的主要例子中的FK的順序) –

+0

如果你想發佈您的域(模型)在您的文章!我也可以有更好的理念! –

4

編寫自己的存儲類是正確的。但get_available_name不是正確的方法來覆蓋。

get_available_name在Django看到名稱相同的文件並嘗試獲取新的可用文件名時被調用。這不是導致重命名的方法。造成該方法的原因是_save。在_save中的評論是相當不錯的,你可以很容易地找到它打開文件與os.O_EXCL標誌寫入,如果相同的文件名已經存在,將會拋出一個OSError。 Django捕獲此錯誤,然後調用get_available_name以獲取新名稱。

所以我認爲正確的方法是重寫_save並調用os.open()而不用標誌os.O_EXCL。修改很簡單,但方法有點長,所以我不把它粘貼在這裏。告訴我,如果你需要更多的幫助:)

+0

這是50行代碼,你必須複製,這是非常糟糕的。覆蓋get_available_name看起來更孤立,更短,並且更安全,因爲將來升級到較新版本的Django –

+1

只有*覆蓋'get_available_name'的問題是當您上載具有相同名稱的文件時,服務器將進入無限循環。由於'_save'檢查文件名並決定獲取一個新的文件名,但是'get_available_name'仍然返回重複的文件名。所以你需要重寫這兩個。 – x1a0

+1

糟糕,我們在兩個問題上討論這個問題,但是現在我注意到它們略有不同)所以我是這個問題的正確答案,並且你在這裏) –

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() 
相關問題