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

时间:2022-11-19 09:27:22

I am having trouble putting together two ideas, resizing an image from models.ImageField (which works fine if I don't try to also upload to my Amazon S3 bucket) and uploading an image to my Amazon S3 bucket).

我无法将两个想法放在一起,从models.ImageField调整图像大小(如果我不尝试上传到我的Amazon S3存储桶,它可以正常工作)并将图像上传到我的Amazon S3存储桶中。

My model:

我的模特:

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

So full_image_large is editable and it is the one that the user is able to upload. I want this photo, regardless of its size to be resized (keeping the aspect ratio) to be 900px in width. Then I am trying to also resize the same photo to full_image which should be 350px in width. Finally, I am trying to resize the same photo to thumbnail_image which should be 120px in width.

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

When I go to my site's admin url and save the object, I am getting the following error.

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

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

The first image gets uploaded to Amazon S3 (if I comment out references to the two other images) just fine but nothing gets resized. If anyone can help me with the easiest way to accomplish what I am doing, that would be appreciated. Thanks. Note: I am using Python3.

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

I have also tried using django-imagekit without success.

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

1 个解决方案

#1


1  

Try using the following instead:

请尝试使用以下代码:

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

You can do all three resize operations on the same Image instance - image in this case. Just save the results of that operation in a new object for each size, then save that object instead of saving the original image object.

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

However, one of Python's main tenets is DRY - Don't Repeat Yourself. The above code can be refactored like so:

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

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 creates a tuple of each width and target.

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

#1


1  

Try using the following instead:

请尝试使用以下代码:

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

You can do all three resize operations on the same Image instance - image in this case. Just save the results of that operation in a new object for each size, then save that object instead of saving the original image object.

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

However, one of Python's main tenets is DRY - Don't Repeat Yourself. The above code can be refactored like so:

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

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 creates a tuple of each width and target.

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