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

Ory*_*and 10 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 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)
Run Code Online (Sandbox Code Playgroud)

我希望能够在模型对象/实例上替换 FileField 视频中的文件.我写的上述方法不起作用.删除原始文件后,出现以下错误:

ValueError: The 'video' attribute has no file associated with it.
Run Code Online (Sandbox Code Playgroud)

如何用更新的文件替换文件,并删除原始文件(不再需要)?

旁注:我发现了一个相关的问题,但没有令人满意的答案.

S.L*_*ott 11

你有两个选择.

我假设你的Project模型只是一段代码.

选项1是打破您的模型,以便项目没有单个文件,而是项目模型与ProjectFile模型相关联.也许一对多.一个项目尽可能多的ProjectFiles.也就是说,ProjectFile有一个ForeigKey to 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)
Run Code Online (Sandbox Code Playgroud)

这可能会做你想要的.

是的,这似乎效率低下.这真的不是那么糟糕.转换需要永远.副本需要时间.


dwu*_*urf 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)
Run Code Online (Sandbox Code Playgroud)