класс, подобный StringIO, расширяющий django.core.files.File - PullRequest
6 голосов
/ 25 июля 2010
class MyModel(models.Model)
 image = models.FileField(upload_to="blagh blagh...")
 #more spam...

У меня есть файл в памяти, и я хочу сохранить его с помощью метода сохранения Django FileField, например:

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

Я пытался использовать StringIO, но он не расширяет django.core.files.File и, следовательно, не реализует метод chunks (). Я обернул его в объект File следующим образом:

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

Но методы File используют поля размера и имени предоставленного файла. StringIO не определяет их. Я нашел это , но ссылка мертва

Ответы [ 4 ]

26 голосов
/ 26 июля 2010

Вы можете использовать ContentFile вместо File

from django.core.files.base import ContentFile

photo.image.save(name, ContentFile(buffer))
8 голосов
/ 13 октября 2011

Ре ответ Джейсона. Обратите внимание, что ContentFile принимает только строки, но не любые файловые объекты. Вот тот, который делает -

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

Теперь вы можете делать такие вещи, как это -

photo.image.save(name, StreamFile(io))
7 голосов
/ 26 июля 2010

Если у вас есть поток байтов, который вы хотите сохранить в FileField / ImageField, вот код, который может помочь:

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

Некоторые заметки:

  • Вы можете придумать любое имя для изображения, но, возможно, захотите сохранить расширение точно
  • Второй аргумент InMemoryUploadedFile - это имя поля в вашей модели, следовательно, "image"

Это немного придирчиво, но оно выполняет свою работу. Будем надеяться, что API будет очищен немного больше в 1.3 / 4.

Edit:
См. ответ Джейсона для более простого способа сделать это, хотя вы все равно захотите узнать имя файла изображения.

0 голосов
/ 26 июля 2010

Используйте класс Изображение .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...