2011-01-24 31 views
9

En Django, tengo el siguiente modelo:Django: ¿Cómo reemplazar/sobrescribir/actualizar/cambiar un archivo de 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) 

Quiero ser capaz de reemplazar el archivo de vídeo en el FileField en un modelo de objeto/instancia. El método anterior que he escrito no funciona. Una vez que elimino el archivo original, me sale el siguiente error:

ValueError: The 'video' attribute has no file associated with it. 

¿Cómo puedo reemplazar el archivo con una actualizada y retire el original (no más necesario)?

Nota-lateral: He encontrado un related issue, pero sin una respuesta satisfactoria.

Respuesta

10

Tiene dos opciones.

Supongo que su modelo Project es solo un fragmento de código.

La opción 1 es dividir su modelo para que un proyecto no tenga un solo archivo, sino que un modelo de proyecto esté asociado con un modelo de ProjectFile. Quizás uno a muchos. Un proyecto como muchos ProjectFiles. Es decir, ProjectFile tiene ForeigKey to Project.

Luego puede agregar un nuevo ProjectFile basado en un antiguo ProjectFile. Puede eliminarlos y engañarlo todo lo que desee. De hecho, puede mantener ambos ProjectFile con un indicador de que es "actual".

Opción 2 es self.video.open("w") para abrir el archivo para escritura. Reescribe los contenidos "en su lugar". En lugar de eliminar y reemplazar el archivo, vuelva a escribir el archivo anterior con el nuevo contenido.

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) 

Eso probablemente haga lo que quiera.

Sí, parece ineficaz. En realidad no está tan mal. La conversión toma para siempre. La copia toma momentos.

+0

Opción 1 Realmente suena como una buena idea. ¡Gracias! –

4

me encontré con este problema recientemente a mí mismo, y lo resolvió así:

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) 
Cuestiones relacionadas