【问题标题】:Django Resize image in FormsDjango 在表单中调整图像大小
【发布时间】:2018-11-21 05:29:20
【问题描述】:

我正在使用 python 3.6 和 Django 2.0。

我有一张方形图像,我想将其上传到模型中。我目前在可以上传的模型中有一个图像字段。

avatar             = models.ImageField(path_and_rename, max_length=255, blank=True

我想将上传的任何方形图像的大小调整为 750 x 750。我想了一种方法来做到这一点,但我认为我没有将它保存为正确的类型,因为它会给我一个错误。

'Image' object has no attribute '_committed'

如何调整方形图像的大小以满足我需要的新尺寸。

我的代码(省略了验证以使其更简单):

forms.py

def clean_avatar(self):
  avatar = self.cleaned_data['avatar']
  try:
    print(len(avatar))
    w, h = get_image_dimensions(avatar)
    max_width = max_height = 750
    image = Image.open(avatar)
    resized_image = image.resize((max_width,max_height), Image.ANTIALIAS)
    print(type(avatar))
    print(type(image))
    print(type(resized_image))
    return resized_image
  except
    ...

上面的输出是

<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
<class 'PIL.JpegImagePlugin.JpegImageFile'>
<class 'PIL.Image.Image'>

如果我返回avatar,它可以工作,但是当我返回resized_image 时它不起作用。如何使resized_image 的数据类型成为avatar 的数据类型?

完整的错误信息:

File "C:\myapp\lib\site-packages\django\core\handlers\exception.py" in inner


35.             response = get_response(request)

File "C:\myapp\lib\site-packages\django\core\handlers\base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "C:\myapp\lib\site-packages\django\core\handlers\base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\myapp\lib\site-packages\django\views\generic\base.py" in view
  69.             return self.dispatch(request, *args, **kwargs)

File "C:\myapp\lib\site-packages\django\contrib\auth\mixins.py" in dispatch
  52.         return super().dispatch(request, *args, **kwargs)

File "C:\myapp\lib\site-packages\django\views\generic\base.py" in dispatch
  89.         return handler(request, *args, **kwargs)

File "C:\myapp\lib\site-packages\django\views\generic\edit.py" in post
  194.         return super().post(request, *args, **kwargs)

File "C:\myapp\lib\site-packages\django\views\generic\edit.py" in post
  142.             return self.form_valid(form)

File "C:\myapp\lib\site-packages\django\views\generic\edit.py" in form_valid
  125.         self.object = form.save()

File "C:\myapp\lib\site-packages\django\forms\models.py" in save
  456.             self.instance.save()

File "C:\myapp\lib\site-packages\django\contrib\auth\base_user.py" in save
  73.         super().save(*args, **kwargs)

File "C:\myapp\lib\site-packages\django\db\models\base.py" in save
  729.                        force_update=force_update, update_fields=update_fields)

File "C:\myapp\lib\site-packages\django\db\models\base.py" in save_base
  759.             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)

File "C:\myapp\lib\site-packages\django\db\models\base.py" in _save_table
  820.                       for f in non_pks]

File "C:\myapp\lib\site-packages\django\db\models\base.py" in <listcomp>
  820.                       for f in non_pks]

File "C:\myapp\lib\site-packages\django\db\models\fields\files.py" in pre_save
  285.         if file and not file._committed:

Exception Type: AttributeError at /account/details/
Exception Value: 'Image' object has no attribute '_committed'

【问题讨论】:

  • 您想自动调整图像大小还是让用户选择他们想要选择图像的哪一部分?
  • Image.open 从(可能)作为文件名的str 对象返回PIL.Image.Image 对象。您可能需要的是使用 .save 和合适的 str 作为临时名称创建一个文件,然后传递它。
  • @BidhanMajhi 我有一些反应代码,可以让用户根据需要裁剪照片。然后我想让他们上传它,然后调整大小。
  • @Kapil 我是保存在表单部分还是保存其他(视图?)

标签: django resize python-imaging-library


【解决方案1】:

我做过类似的事情,但不是形式。我的做法是这样的:

# override Model Save Method

class YourModel(models.Model):
  ...
  def save(self, **kwargs):
     resize = kwargs.pop('resize', False)
     instance = super(YourModel, self).save(**kwargs)
     if resize:
        pil_image = Image.open(self.avatar.path)
        # resize related code
        resized_image = pil_image.resize((max_width,max_height), Image.ANTIALIAS)
        resized_image.save(self.avatar.path)

     return instance

并从这样的表单中调用此保存方法:

 class YourForm(...):
     ...
     def save(self, commit=True):
        instance = super(YourForm, self).save(commit=False)
        instance.save(resize=True)  # call model save method from here
        return instance

更新

也许你可以这样尝试:

import io 

# clean method
w, h = get_image_dimensions(avatar)
max_width = max_height = 750
image = Image.open(avatar)
resized_image = image.resize((max_width,max_height), Image.ANTIALIAS)
img_in_memory = io.BytesIO()
resized_image.save(img_in_memory, format="png")
return img_in_memory

【讨论】:

  • 我试过这个,对于这一行 pil_image = Image.open(self.avatar.path) 我收到一条错误消息 - this back end doesn't support absolute paths。我正在使用 s3 来保存我的文件。明天会调查这个。
  • 我看到另一篇帖子说要将其更改为 self.avatar.name,但是当我这样做时却说该文件不存在(因为我还没有保存它)。令人困惑。
  • @MicahPearce 请参阅我的答案更新部分。希望有帮助!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-01
  • 2017-06-26
  • 2015-08-06
  • 1970-01-01
  • 2011-10-24
  • 1970-01-01
  • 2018-10-20
相关资源
最近更新 更多