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

Ich habe eine Datei im Speicher, und ich möchte speichern es über Django Filefield Methode speichern, wie dies erweitert:ein StringIO wie Klasse, die django.core.files.File

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

I‘ Ich habe versucht, StringIO zu verwenden, aber es erweitert django.core.files.File nicht und implementiert daher nicht die Methode chunks(). Ich habe es in ein File-Objekt wie das eingewickelt:

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

Aber Dateimethoden verwenden Größe und Name Felder der gelieferten Datei. StringIO definiert sie nicht. Ich habe gefunden this, aber die Verbindung ist tot

Antwort

7

Wenn Sie einen Stream von Bytes haben, die Sie zu einem Filefield/Imagefield speichern möchten, hier einige Code, die helfen könnten:

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

Einige Anmerkungen:

  • Sie können den gewünschten Namen für das Bild erstellen, aber Sie möchten die Erweiterung wahrscheinlich genau behalten
  • Das zweite Argument zu InMemoryUploadedFile ist der Name des Feldes in Ihrem Modell, daher "image"

Es ist ein wenig finicky, aber es macht die Arbeit erledigt. Hoffentlich wird die API in 1.3/4 etwas aufgeräumt.

Edit:
Siehe Jason's answer für eine viel einfachere Art und Weise, dies zu tun, wenn Sie immer noch die Dateinamen des Bildes wissen wollen, werden.

+0

Danke Mann :) – exshinigami

0

Verwenden Sie die Image Klasse.

+0

ich der Auffassung, dass, aber dann würde ich nicht django Mechanismus für die Benennung von Dateien (wenn eine Datei mit einem bestimmten verwenden Name existiert, fügen Sie dem Dateinamen einen Unterstrich hinzu). Und ja, ich weiß, ich könnte das alleine machen, und ich könnte das auf andere Weise tun, aber es wäre das Beste, wenn ich das täte, wie ich es vorher beschrieben habe. – joozek

26

können Sie ContentFile statt

Datei verwenden
from django.core.files.base import ContentFile 

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

Ordentlich! Das ist so viel einfacher als meine Lösung ... + 1 – elo80ka

7

Antwort des Re Jason. Beachten Sie, dass ContentFile nur Zeichenfolgen und keine dateiähnlichen Objekte akzeptiert. Hier ist eine, die funktioniert -

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

Jetzt können Sie Sachen wie diese tun -

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

Dies ist die eigentliche richtige Antwort, gerettet meinen Tag! – danigosa

+0

FWIW, heutzutage akzeptiert 'ContentFile' auch Bytes. –

Verwandte Themen