开发者

a StringIO like class, that extends django.core.files.File

开发者 https://www.devze.com 2023-01-09 00:20 出处:网络
class MyModel(models.Model) image = models.FileField(upload_to=\"blagh blagh...\") #more spam... I have a file in memory and I want to save it via Django FileField save method, like this:
class MyModel(models.Model)
 image = models.FileField(upload_to="blagh blagh...")
 #more spam...

I have a file in memory and I want to save it via Django FileField save method, like this:

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

I've tried to use StringIO, but it doesn't extend django.core.files.File and thus doesn't implement method chunks(). I've wrapped it in a File object like that:

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

But File 开发者_StackOverflow中文版methods use size and name fields of supplied file. StringIO doesn't define them. I've found this, but the link is dead


You can use ContentFile instead of File

from django.core.files.base import ContentFile

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


If you've got a stream of bytes, which you'd like to save to a FileField/ImageField, here's some code that might help:

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

Some notes:

  • You can make up whatever name you want for the image, but you'll probably want to keep the extension accurate
  • The second argument to InMemoryUploadedFile is the name of the field in your model, hence "image"

It's a little finnicky, but it gets the job done. Hopefully, the API will get cleaned up a bit more in 1.3/4.

Edit:
See Jason's answer for a much simpler way of doing this, though you'll still want to know the filename of the image.


Re Jason's answer. Note that ContentFile only accepts strings, not any file-like object. Here's one that does --

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

Now you can do stuff like this --

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

精彩评论

暂无评论...
验证码 换一张
取 消