如何使用Django调整用户图像的大小并上传到Amazon S3?

时间:2015-04-12 17:41:23

标签: django python-3.x amazon-s3

我无法将两个想法放在一起,从models.ImageField调整图片大小(如果我不尝试上传到我的Amazon S3广告管理系统,则可以正常工作)并将图片上传到我的Amazon S3桶)。

我的模特:

from django.db import models
from django.conf import settings
from storages.backends.s3boto import S3BotoStorage
from django.core.files.storage import default_storage as storage
import datetime
from PIL import Image
import math

class Artwork(models.Model):
    title = models.CharField(max_length=200)

    # other fields...

    full_image_large = models.ImageField(storage=S3BotoStorage(location='img'))
    full_image = models.ImageField(storage=S3BotoStorage(location='img'), editable=False)
    thumbnail_image = models.ImageField(storage=S3BotoStorage(location='img'), editable=False)

    def __str__(self):
        return self.title

    def save(self):
        super(Artwork, self).save()
        image = Image.open(self.full_image_large, 'r')
        (w, h) = image.size
        for width, target in zip([900.0, 350.0, 120.0], 
                                 [self.full_image_large,  
                                  self.full_image, 
                                  self.thumbnail_image]):
            r = width/w
            im = image.resize((int(math.floor(r*w)), 
                               int(math.floor(r*h))), 
                               Image.ANTIALIAS)
            im.save(target, format='JPEG')

因此full_image_large是可编辑的,用户可以上传。我想要这张照片,不管它的大小是否要调整大小(保持宽高比)宽度为900px。然后我也尝试将同一张照片的大小调整为full_image,宽度应为350像素。最后,我正在尝试将同一张照片的大小调整为thumbnail_image,宽度应为120像素。

当我访问我网站的管理员网址并保存对象时,我收到以下错误消息。

The 'full_image' attribute has no file associated with it.

第一张图片上传到Amazon S3(如果我注释掉对其他两张图片的引用)就好了,但没有任何内容可以调整大小。如果有人能用最简单的方法帮助我完成我正在做的事情,那将不胜感激。谢谢。注意:我使用的是Python3。

我也试过使用django-imagekit但没有成功。

1 个答案:

答案 0 :(得分:1)

请尝试使用以下内容:

def save(self):
    image = Image.open(self.full_image_large)
    (w, h) = image.size
    r900 = 900.0/w
    im900 = image.resize((int(math.floor(r900*w)), int(math.floor(r900*h))), Image.ANTIALIAS)
    im900.save(self.full_image_large)

    r350 = 350.0/w
    im350 = image.resize((int(math.floor(r350*w)), int(math.floor(r350*h))), Image.ANTIALIAS)
    im350.save(self.full_image)

    r120 = 120.0/w
    im120 = image.resize((int(math.floor(r120*w)), int(math.floor(r120*h))), Image.ANTIALIAS)
    im120.save(self.thumbnail_image)

    super(Artwork, self).save()

在这种情况下,您可以在同一resize个实例 - Image上执行所有三项image操作。只需将该操作的结果保存在每个大小的新对象中,然后保存对象,而不是保存原始image对象。

然而,Python的主要原则之一就是DRY - Don不要重复自己。上面的代码可以像这样重构:

def save(self):
    image = Image.open(self.full_image_large)
    (w, h) = image.size
    for width, target in zip([900.0, 350.0, 120.0], 
                             [self.full_image_large, 
                              self.full_image, 
                              self.thumbnail_image]):
        r = width/w
        im = image.resize((int(math.floor(r*w)), 
                           int(math.floor(r*h))), 
                           Image.ANTIALIAS)
        im.save(target)

    super(Artwork, self).save()

zip创建每个宽度和目标的元组。