2011-01-24 194 views
9

在Django中,我有以下型號:Django:如何替換/覆蓋/更新/更改FileField的文件?

from django.db import models 
from django.core.files.base import File 
import os, os.path 

class Project(models.Model): 
    video = models.FileField(upload_to="media") 

    def replace_video(self): 
     """Convert video to WebM format.""" 
     # This is where the conversion takes place, 
     # returning a path to the new converted video 
     # that I wish to override the old one. 
     video_path = convert_video() 

     # Replace old video with new one, 
     # and remove original unconverted video and original copy of new video. 
     self.video.delete(save=True) 
     self.video.save(os.path.basename(video_path), File(open(video_path ,"wb")), save=True) 
     os.remove(video_path) 

我希望能夠取代文件中的模型對象/實例的FileField 視頻。我寫的上述方法不起作用。一旦我刪除原始文件,我得到以下錯誤:

ValueError: The 'video' attribute has no file associated with it. 

我如何爲一個更新替換該文件,並刪除原來的(沒有更多必要的)?

Side-Note:我找到了related issue,但沒有滿意的答案。

回答

10

你有兩種選擇。

我假設你的Project模型只是一段代碼。

選項1是打破你的模型,使一個項目沒有一個文件,而是一個項目模型與ProjectFile模型相關聯。也許是一對多的。一個項目與許多ProjectFiles一樣。也就是說,ProjectFile有一個ForeigKey到Project。

然後,您可以基於舊的ProjectFile添加新的ProjectFile。你可以刪除它們,並在你想要的任何地方混淆。事實上,你可以保持兩個ProjectFile的指標是「當前」。

選項2是以self.video.open("w")打開文件進行寫入。重寫內容「到位」。用新內容重寫舊文件,而不是刪除和替換文件。

with open(video_path ,"rb") as source: 
    self.video.open("wb") 
    bytes= source.read(4096) 
    if bytes: 
     self.video.write(bytes) 
     bytes= source.read(4096) 

這可能會做你想做的。

是的,它似乎效率低下。這真的不是那麼糟糕。轉換需要永遠。副本需要時間。

+0

選項1聽起來真的是一個好主意。謝謝! – 2011-01-25 11:21:59

4

我遇到這個問題來到最近自己,解決了這個問題是這樣的:

from django.db import models 
from django.core.files.base import File 
import os, os.path 

class Project(models.Model): 
    video = models.FileField(upload_to="media") 

    def replace_video(self): 
     """Convert video to WebM format.""" 
     # This is where the conversion takes place, 
     # returning a path to the new converted video 
     # that I wish to override the old one. 
     video_path = convert_video() 

     # Replace old video with new one, 
     # and remove original unconverted video and original copy of new video. 
     old_path = self.video.path 
     self.video.save(os.path.basename(video_path), File(open(video_path ,"wb")), save=True) 
     os.remove(video_path) 
     os.remove(old_path)