fia*_*cre 7 python django amazon-s3 image-resizing python-imaging-library
我继承了一个Django项目,我们已将图像移动到S3
其中一个模型是典型的用户配置文件
class Profile(UUIDBase):
first_name = models.CharField(_("First Name"), max_length=20)
last_name = models.CharField(_("Last Name"), max_length=20, null=True)
profile_image = models.ImageField(
_("Profile Image"),
upload_to=profile_image_name,
max_length=254,
blank=True,
null=True
)
profile_image_thumb = models.ImageField(
_("Profile Image Thumbnail"),
upload_to=profile_image_name,
max_length=254,
blank=True,
null=True
)
... other fields
Run Code Online (Sandbox Code Playgroud)
profile_image_name功能在哪里:
def profile_image_name(instance, filename):
if filename:
target_dir = 'uploads/profile_img/'
_, ext = filename.rsplit('.', 1)
filename = str(instance.uid) + '.' + ext
return '/'.join([target_dir, filename])
Run Code Online (Sandbox Code Playgroud)
我有一些有用的代码:
@shared_task
def resize_image(image_path, dim_x, append_str='_resized', **kwargs):
'''
resize any image_obj while maintaining aspect ratio
'''
orig = storage.open(image_path, 'r')
im = Image.open(orig, mode='r')
new_y = (float(dim_x) * float(im.height)) / float(im.width)
new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS)
img_path, img_name = path.split(image_path)
file_name, img_ext = img_name.rsplit('.', 1)
new_img_path = path.join(img_path, file_name + append_str + '.' + img_ext)
try:
new_f = storage.open(new_img_path, 'w')
except IOError as e:
logger.critical("Caught IOError in {}, {}".format(__file__, e))
ravenclient.captureException()
return None
try:
new_im.save(new_f)
except IOError as e:
logger.critical("Caught IOError in {}, {}".format(__file__, e))
ravenclient.captureException()
return None
except Exception as e:
logger.critical("Caught unhandled exception in {}. {}".format(
__file__, e)
)
ravenclient.captureException()
return None
im.close()
new_im.close()
new_f.close()
return new_img_path
Run Code Online (Sandbox Code Playgroud)
这是从post_save信号处理程序调用的:
@receiver(post_save, sender=Profile, dispatch_uid='resize_profile_image')
def resize_profile_image(sender, instance=None, created=False, **kwargs):
if created:
if instance.profile_image:
width, height = image_dimensions(instance.profile_image.name)
print(width, height)
if width > MAX_WIDTH:
result = resize_image.delay(instance.profile_image.name, MAX_WIDTH)
instance.profile_image.name = result.get()
if width > THUMB_WIDTH:
result = resize_image.delay(
instance.profile_image.name,
THUMB_WIDTH,
append_str='_thumb'
)
instance.profile_image_thumb.name = result.get()
try:
instance.save()
except Exception as e:
log.critical("Unhandled exception in {}, {}".format(__name__, e))
ravenclient.captureException()
Run Code Online (Sandbox Code Playgroud)
目的是获取上传的图像并将它们调整大小1)到移动设备可以显示的最大宽度,以及2)到移动应用程序中使用的50像素缩略图.
当我查看S3时,我看不到我调整大小的图像或缩略图.然而,单元测试(彻底的)不会给出任何错误.
当我得到图像尺寸时:
def image_dimensions(image_path):
f = storage.open(image_path, 'r')
im = Image.open(f, 'r')
height = im.height
width = im.width
im.close()
f.close()
return (width, height)
Run Code Online (Sandbox Code Playgroud)
访问对象的ImageField没有问题.当我使用default_storage打开实例的profile_image时,我没有收到任何错误.PIL方法
new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS) 确实返回类'PIL.Image.Image'的新实例.
事实上(原谅我的冗长)
这不会引发错误:
>>> u = User(email="root@groupon.com", password="sdfbskjfskjfskjdf")
>>> u.save()
>>> p = Profile(user=u, profile_image=create_image_file())
>>> p.save()
>>> from django.core.files.storage import default_storage as storage
>>> orig = storage.open(p.profile_image.name, 'r')
>>> orig
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19.jpg>
>>> im = Image.open(orig, mode='r')
>>> im
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=5000x5000 at 0x10B8F1FD0>
>>> im.__class__
<class 'PIL.JpegImagePlugin.JpegImageFile'>
>>> dim_x = 500
>>> new_y = (float(dim_x) * float(im.height)) / float(im.width)
>>> new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS)
>>> new_im.__class__
<class 'PIL.Image.Image'>
>>> img_path, img_name = path.split(p.profile_image.name)
>>> file_name, img_ext = img_name.rsplit('.', 1)
>>> append_str='_resized'
>>> new_img_path = path.join(img_path, file_name + append_str + '.' + img_ext)
>>> new_f = storage.open(new_img_path, 'w')
>>> new_f
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19_resized.jpg>
>>> new_im.save(new_f) #### This does NOT create an S3 file!!!!
>>> im.close()
>>> new_im.close()
>>> new_f.close()
Run Code Online (Sandbox Code Playgroud)
>>> p.save()将新的个人资料图像上传到S3.我原本希望>>> new_im.save(new_f)将Image文件写入S3.但事实并非如此.
非常感谢任何见解或帮助,并感谢您花时间来研究这个问题.
编辑...
我的设置:
AWS_STORAGE_BUCKET_NAME = 'testthis'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
MEDIAFILES_LOCATION = 'media'
MEDIA_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, MEDIAFILES_LOCATION)
DEFAULT_FILE_STORAGE = 'custom_storages.MediaStorage'
Run Code Online (Sandbox Code Playgroud)
custom_storage.py的位置
from django.conf import settings
from storages.backends.s3boto import S3BotoStorage
class MediaStorage(S3BotoStorage):
location = settings.MEDIAFILES_LOCATION
bucket_name = settings.AWS_STORAGE_BUCKET_NAME
Run Code Online (Sandbox Code Playgroud)
该问题似乎与 PIL 的 JPEG 库有关:
>>> u = User(email="root@groupon.com", password="sdfbskjfskjfskjdf")
>>> u.save()
>>> p = Profile(user=u, profile_image=create_image_file())
>>> p.save()
>>> from django.core.files.storage import default_storage as storage
>>> orig = storage.open(p.profile_image.name, 'r')
>>> orig
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19.png>
>>> im = Image.open(orig, mode='r')
>>> im.__class__
<class 'PIL.PngImagePlugin.PngImageFile'>
>>> dim_x = 500
>>> new_y = (float(dim_x) * float(im.height)) / float(im.width)
>>> new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS)
>>> new_im.__class__
<class 'PIL.Image.Image'>
>>> img_path, img_name = path.split(p.profile_image.name)
>>> file_name, img_ext = img_name.rsplit('.', 1)
>>> append_str='_resized'
>>> new_img_path = path.join(img_path, file_name + append_str + '.' + img_ext)
>>> new_f = storage.open(new_img_path, 'w')
>>> new_f
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19_resized.png>
>>> new_im.save(new_f) #### This does create a file on S3!
>>> im.close()
>>> new_im.close()
>>> new_f.close()
Run Code Online (Sandbox Code Playgroud)