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

Mam plik w pamięci i chcę zapisać go poprzez Django FileField zapisać metodę, tak:StringIO jak klasy, która rozciąga się django.core.files.File

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

I ve próbował użyć StringIO, ale nie rozszerza pliku django.core.files.File, a tym samym nie implementuje metody chunks(). Zawinęłam go w obiekt File w następujący sposób:

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

Ale metody plików używają pól rozmiaru i nazwy dostarczonego pliku. StringIO ich nie definiuje. Znalazłem this, ale link jest martwy

Odpowiedz

7

Jeśli masz strumień bajtów, których chcesz się zapisać do FileField/ImageField, oto niektóre kod, który może pomóc:

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

Kilka uwag:

  • Możesz nadać dowolną nazwę dla obrazu, ale prawdopodobnie będziesz chciał zachować dokładność rozszerzenia
  • Drugi argument na InMemoryUploadedFile to nazwa pola w twoim modelu, stąd "obraz"

To trochę drobnostka, ale wykonuje swoją robotę. Mam nadzieję, że API zostanie oczyszczone nieco bardziej w wersji 1.3/4.

Edit:
Zobacz Jason's answer o wiele prostszy sposób to zrobić, choć nadal będziesz chciał znać nazwę pliku obrazu.

+0

Dziękuję człowieku :) – exshinigami

0

Użyj klasy Image.

+0

Uważałem, ale wtedy nie byłoby użyć mechanizmu django nazewnictwa plików (jeśli plik z danym nazwa istnieje, dodaj podkreślenie do nazwy pliku). I tak, wiem, mogłem zrobić to sam i mogłem to zrobić w inny sposób, ale byłoby najlepiej, gdybym to zrobił, jak opisałem wcześniej. – joozek

26

Można użyć ContentFile zamiast pliku

from django.core.files.base import ContentFile 

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

Schludny! To jest o wiele prostsze niż moje rozwiązanie ... + 1 – elo80ka

7

odpowiedź Re Jasona. Zauważ, że ContentFile akceptuje tylko łańcuchy, a nie jakikolwiek obiekt podobny do pliku. Oto ten, który robi -

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

Teraz można robić takie rzeczy -

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

To jest prawdziwa poprawna odpowiedź, uratowałem mój dzień! – danigosa

+0

FWIW, obecnie "ContentFile" również akceptuje bajty. –

Powiązane problemy