2010-07-25 14 views
6
class MyModel(models.Model) 
image = models.FileField(upload_to="blagh blagh...") 
#more spam... 

Tengo un archivo en la memoria y quiero guardarlo a través de Django FileField ahorrar método, como esto:un StringIO como la clase, que se extiende django.core.files.File

photo.image.save(name, buffer) # second arg should be django File 

I' he intentado usar StringIO, pero no extiende django.core.files.File y, por lo tanto, no implementa los trozos de método(). Me he envuelto en un objeto File así:

buffile = File(buffer, name) # first argument should be a file 
photo.image.save(name, buffile) 

Pero Archivo métodos utilizan campos de tamaño y el nombre del archivo suministrado. StringIO no los define. He encontrado this, pero el enlace está muerto

Respuesta

7

Si usted tiene un flujo de bytes, que le gustaría guardar en un FileField/ImageField, aquí hay un código que podría ayudar:

>>> from django.core.files.uploadedfile import InMemoryUploadedFile 
>>> from cStringIO import StringIO 
>>> buf = StringIO(data) # `data` is your stream of bytes 
>>> buf.seek(0, 2) # Seek to the end of the stream, so we can get its length with `buf.tell()` 
>>> file = InMemoryUploadedFile(buf, "image", "some_filename.png", None, buf.tell(), None) 
>>> photo.image.save(file.name, file) # `photo` is an instance of `MyModel` 
>>> photo.image 
<ImageFieldFile: ...> 

Algunas notas:

  • Puede inventar el nombre que desee para la imagen, pero es probable que desee mantener la extensión correcta
  • El segundo argumento para InMemoryUploadedFile es el nombre del campo en su modelo, de ahí "imagen"

Es un poco exigente, pero hace el trabajo bien. Con suerte, la API se limpiará un poco más en 1.3/4.

Editar:
Ver Jason's answer de una manera mucho más sencilla de hacer esto, aunque todavía querrá saber el nombre del archivo de la imagen.

+0

Gracias hombre :) – exshinigami

0

Utilice la clase Image.

+0

que consideró que, pero entonces yo no usaría Django mecanismo para nombrar los archivos (si es un archivo con una determinada nombre existe, agregue subrayado al nombre del archivo). Y sí, lo sé, podría hacerlo yo solo y podría hacerlo de otra manera, pero sería lo mejor si lo hiciera, como lo describí antes. – joozek

26

Se puede utilizar en lugar de ContentFile Archivo

from django.core.files.base import ContentFile 

photo.image.save(name, ContentFile(buffer)) 
+3

¡Neto! Esto es mucho más simple que mi solución ... + 1 – elo80ka

7

respuesta de Re Jason. Tenga en cuenta que ContentFile solo acepta cadenas, no cualquier objeto similar a un archivo. Aquí hay uno que lo haga -

from django.core.files.base import * 

class StreamFile(ContentFile): 
    """ 
    Django doesn't provide a File wrapper suitable 
    for file-like objects (eg StringIO) 
    """ 
    def __init__(self, stream): 
     super(ContentFile, self).__init__(stream) 
     stream.seek(0, 2) 
     self.size = stream.tell() 

Ahora usted puede hacer cosas como esta -

photo.image.save(name, StreamFile(io)) 
+0

Esta es la respuesta correcta, ¡salvó mi día! – danigosa

+0

FWIW, hoy en día 'ContentFile' también acepta bytes. –

Cuestiones relacionadas