Python Django:如何替换/覆盖/更新/更改FileField的文件?

Python Django:如何替换/覆盖/更新/更改FileField的文件?,python,django,django-models,Python,Django,Django Models,在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 form

在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视频中的文件。我写的上述方法不起作用。删除原始文件后,会出现以下错误:

ValueError: The 'video' attribute has no file associated with it.
如何用更新的文件替换该文件,并删除原始文件(不再需要)

旁注:我找到了一个答案,但没有令人满意的答案。

你有两个选择

我假设您的
项目
模型只是一段代码

选项1是分解模型,使项目没有单个文件,而是将项目模型与项目文件模型关联。也许是一对多。一个项目等于多个项目文件。也就是说,ProjectFile有一个foreiggey用于Project

然后,您可以基于旧项目文件添加新项目文件。你可以删除它们,想干什么就干什么。实际上,您可以将两个项目文件都保留为带有“当前”指示器的项目文件

选项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)
那可能会满足你的要求


是的,似乎效率很低。其实没那么糟。这种转变永远需要时间。复制需要一些时间

我最近自己遇到了这个问题,并解决了它,就像这样:

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)