2011-01-24 156 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)