Django: 如何替换/更新/FileField的文件?
在Django中,我有一个这样的模型:
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 video中替换文件。我写的方法没有成功。一旦我删除了原始文件,就会出现以下错误:
ValueError: The 'video' attribute has no file associated with it.
我该如何用更新的文件替换原来的文件,并且删除原来的文件(不再需要)呢?
附注:我找到一个相关的问题,但没有得到令人满意的答案。
3 个回答
0
另一种解决办法是删除原来的模型实例,然后创建一个新的。
比如说:
def upload_metadata(request):
if request.method == 'POST':
try: # removes existing file
uf = UserFile.objects.get(
library_id = request.POST['library_id'],
file = 'uploads/' + request.FILES['file']._get_name())
uf.delete()
except Exception as e:
pass
# ... continue with form handling as before ...
5
我最近也遇到了这个问题,最后是这样解决的:
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)
12
你有两个选择。
我假设你的 Project
模型只是代码的一小部分。
选择一是把你的模型拆分开来,让一个项目(Project)不再只有一个文件,而是和多个项目文件(ProjectFile)关联。也就是说,一个项目可以有多个项目文件。具体来说,项目文件里有一个外键(ForeignKey)指向项目。
这样你就可以根据旧的项目文件添加新的项目文件。你可以删除它们,随便操作。实际上,你可以保留两个项目文件,并标记哪个是“当前”的。
选择二是用 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)
这样做可能就能达到你想要的效果。
是的,这看起来效率不高,但其实并没有那么糟糕。转换过程可能很慢,但复制文件只需要几秒钟。