Django: Как заменить / перезаписать / обновить / изменить файл FileField? - PullRequest
9 голосов
/ 25 января 2011

В 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.

Как заменить файл на обновленный и удалить исходный (больше не нужно)?

Примечание : Я обнаружил связанную проблему , но без удовлетворительного ответа.

Ответы [ 2 ]

11 голосов
/ 25 января 2011

У вас есть два варианта.

Я предполагаю, что ваша 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)

Это, вероятно, будет делать то, что вы хотите.

Да, это кажется неэффективным. Это действительно не так уж и плохо. Преобразование занимает вечность. Копия занимает минуты.

4 голосов
/ 13 февраля 2013

Я недавно столкнулся с этой проблемой и решил ее примерно так:

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)
...