2011-01-24 2 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 для проекта.

Затем вы можете добавить новый 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 действительно звучит как хорошая идея. Благодаря! –

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) 
Смежные вопросы