Django 使用boto将枕头文件保存到S3

Django 使用boto将枕头文件保存到S3,django,amazon-s3,pillow,Django,Amazon S3,Pillow,我通过s3boto使用AmazonS3作为我的存储后端。我有一个带有ImageField的图像模型。当通过管理员上传图像时,它将成功上传到S3。我现在要做的是创建一个缩略图后保存使用枕头。我已经验证了缩略图是通过调用show()方法创建的,但是由于某些原因,它没有上传到S3。我认为我保存它的方式可能是错误的-任何建议将不胜感激 任务。py from celery import shared_task from .models import Image import os from django.

我通过s3boto使用AmazonS3作为我的存储后端。我有一个带有ImageField的图像模型。当通过管理员上传图像时,它将成功上传到S3。我现在要做的是创建一个缩略图后保存使用枕头。我已经验证了缩略图是通过调用show()方法创建的,但是由于某些原因,它没有上传到S3。我认为我保存它的方式可能是错误的-任何建议将不胜感激

任务。py

from celery import shared_task
from .models import Image
import os
from django.core.files.storage import default_storage as storage
from PIL import Image as PillowImage

@shared_task
def create_thumbnails(pk):
    try:
        image = Image.objects.get(pk=pk)
    except Image.ObjectDoesNotExist:
        pass
    thumbnail_size = (450,200)
    filename, ext = os.path.splitext(image.image.name)
    try:
        fh = storage.open(image.image.name, 'r')
        im = PillowImage.open(fh)
        im.thumbnail(thumbnail_size)
        im.show() # TEST - This opens the resized image in Preview on my mac
        filename = filename +'_thumbnail' +ext
        new_file = storage.open(filename, 'w')
        im.save(new_file, "PNG")
        new_file.close()
    except IOError as error:
        print("cannot create thumbnail for ", filename, 'error ', error)
from celery import shared_task
import os
from django.core.files.storage import default_storage as storage
from django.conf import settings
import mimetypes
import cStringIO
from PIL import Image as PillowImage
import boto
from .models import Image

@shared_task
def create_thumbnails(pk):
    try:
        image = Image.objects.get(pk=pk)
    except Image.ObjectDoesNotExist:
        pass
    try:
        thumbnail_size = (450,200)
        filename, ext = os.path.splitext(image.image.name)
        filename = filename +'_thumbnail' +ext
        existing_file = storage.open(image.image.name, 'r')
        im = PillowImage.open(existing_file)
        im = im.resize(thumbnail_size, PillowImage.ANTIALIAS)
        memory_file = cStringIO.StringIO()
        mime = mimetypes.guess_type(filename)[0]
        plain_ext = mime.split('/')[1]
        im.save(memory_file, plain_ext)

        conn  = boto.connect_s3(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
        bucket = conn.get_bucket( 'yourbucketname', validate=False)
        k = bucket.new_key('media/' +filename)
        k.set_metadata('Content-Type', mime)
        k.set_contents_from_string(memory_file.getvalue())
        k.set_acl("public-read")
        memory_file.close()
    except Exception as error:
        print("cannot create thumbnail for ", filename, 'error ', error)
堆栈

django 1.85


python 2.7.10

经过几个小时痛苦的谷歌搜索后,终于可以运行了,这主要要归功于博客文章

任务。py

from celery import shared_task
from .models import Image
import os
from django.core.files.storage import default_storage as storage
from PIL import Image as PillowImage

@shared_task
def create_thumbnails(pk):
    try:
        image = Image.objects.get(pk=pk)
    except Image.ObjectDoesNotExist:
        pass
    thumbnail_size = (450,200)
    filename, ext = os.path.splitext(image.image.name)
    try:
        fh = storage.open(image.image.name, 'r')
        im = PillowImage.open(fh)
        im.thumbnail(thumbnail_size)
        im.show() # TEST - This opens the resized image in Preview on my mac
        filename = filename +'_thumbnail' +ext
        new_file = storage.open(filename, 'w')
        im.save(new_file, "PNG")
        new_file.close()
    except IOError as error:
        print("cannot create thumbnail for ", filename, 'error ', error)
from celery import shared_task
import os
from django.core.files.storage import default_storage as storage
from django.conf import settings
import mimetypes
import cStringIO
from PIL import Image as PillowImage
import boto
from .models import Image

@shared_task
def create_thumbnails(pk):
    try:
        image = Image.objects.get(pk=pk)
    except Image.ObjectDoesNotExist:
        pass
    try:
        thumbnail_size = (450,200)
        filename, ext = os.path.splitext(image.image.name)
        filename = filename +'_thumbnail' +ext
        existing_file = storage.open(image.image.name, 'r')
        im = PillowImage.open(existing_file)
        im = im.resize(thumbnail_size, PillowImage.ANTIALIAS)
        memory_file = cStringIO.StringIO()
        mime = mimetypes.guess_type(filename)[0]
        plain_ext = mime.split('/')[1]
        im.save(memory_file, plain_ext)

        conn  = boto.connect_s3(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
        bucket = conn.get_bucket( 'yourbucketname', validate=False)
        k = bucket.new_key('media/' +filename)
        k.set_metadata('Content-Type', mime)
        k.set_contents_from_string(memory_file.getvalue())
        k.set_acl("public-read")
        memory_file.close()
    except Exception as error:
        print("cannot create thumbnail for ", filename, 'error ', error)

这非常有用,我用它找到了一种从django将图像写入s3的方法,而无需直接使用boto

基本上,PIL的save()方法不适用于s3,但默认的_storage.write()方法适用于s3。关键是使用默认的_storage.write()方法直接从StringIO内存文件写入二进制数据,如下所示:

file_to_write.write(memory_file.getvalue())
下面是我在django shell(python manage.py shell)中运行的代码,用于测试这一点:

>>> from django.core.files.storage import default_storage as storage
>>> from PIL import Image
>>> import StringIO
>>> i = storage.open('ImageToCreate.jpg','w+')
>>> m = storage.open('ImageAlreadyOnS3.jpg','r')
>>> im = Image.open(m)
>>> im = im.resize((640,360),3)
>>> sfile = StringIO.StringIO() #cStringIO works too
>>> im.save(sfile, format="JPEG")
>>> i.write(sfile.getvalue())
>>> i.close()
>>> m.close()
它在my views.py中也起作用

我发现它很有用,因为它可以在远程s3存储和本地开发环境(笔记本电脑上的一个文件夹)上工作。

我也有同样的问题

default_storage.write() # It didn't work. it was not saving anything to s3 
@RunLoop的答案非常复杂,与我想用Django做的不同,所以我做了这个,它成功了

    import StringIO
    from PIL import Image
首先,读取上传的文件

    image = request.FILES['image'].read()  #atleast in my case 
创建一个类似文件的对象,以便我们可以使用图像来读取它

    image_file = StringIO.StringIO(image)
    thumbnail_image = Image.open(image_file)
将图像调整为所需大小

    resized_thumbnail_image = thumbnail_image.resize((200, 200), Image.ANTIALIAS)
创建另一个文件,比如object或inmemory文件,这样我们就可以将映像实例写入其中,并获取字符串值——该值应该传递给默认存储

    resized_thumbnail_image_file = StringIO.StringIO()
    resized_thumbnail_image.save(resized_thumbnail_image_file, 'JPEG',quality=90)

    default_storage.save(save_path, ContentFile(resized_thumbnail_image_file.getvalue()))
我的第一个详细答案,希望能有所帮助

堆栈: python 2.7
Django 1.8
请注意,对于Python3,您可能希望使用BytesIO:

from io import BytesIO

# 'image' is a PIL image object.

imageBuffer = BytesIO()
image.save(imageBuffer, format=imageType)

imageFile = default_storage.open(imageFileName, 'wb')
imageFile.write(imageBuffer.getvalue())
imageFile.flush()
imageFile.close()

这是我在这里看到的最有用的答案之一,真不敢相信我是第一个投赞成票的人