如何在Python Django模型中保存ImageField图像之前调整图像大小

20
我正试图为Django的ImageField类函数实现调整图像大小的功能,但我不确定该函数在哪里接受我的新图像尺寸。
运行在Linux和Python 3.7上。
我查看了这份文档,但并不能完全理解它:https://docs.djangoproject.com/en/1.11/_modules/django/db/models/fields/files/#ImageField 如果有人可以给我展示如何使用此函数的示例,我将非常感激。
编辑:
我还没有成功地调整图像大小,这正是我想要实现的。在保存由ImageField获取的图像之前,如何调整此图像的大小(我找到了ImageField的update_dimensions_fields类函数,但我不知道如何使用它)。
class Posts(models.Model):
    title = models.CharField(max_length=200, blank=True)
    body = models.TextField(blank=True)
    created_at = models.DateTimeField(default=datetime.datetime.now)
    post_image = models.ImageField(upload_to=get_image_path, blank=True, null=True)

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        # I would like to use the function beneath to resize my images before I save them to my database
        self.post_image.update_dimension_fields(self, instance, force=False, *args, **kwargs)

        super().save(*args, **kwargs) # Call the "real" save() method.

    class Meta:
        verbose_name_plural = "Posts"

4个回答

26

您可以使用django-resized库。它可以在上传图片时自动调整大小并为您存储。

使用方法

from django_resized import ResizedImageField

class Posts(models.Model):
    title = models.CharField(max_length=200, blank=True)
    body = models.TextField(blank=True)
    created_at = models.DateTimeField(default=datetime.datetime.now)
    post_image = ResizedImageField(size=[500, 300], upload_to=get_image_path, blank=True, null=True)

    def __str__(self):
        return self.title

选项

  • size - 最大宽度和高度,例如 [640, 480]
  • crop - 调整大小并裁剪。['top', 'left'] - 上左角,['middle', 'center'] - 居中裁剪,['bottom', 'right'] - 裁剪右下角。
  • quality - 调整大小后图像的质量,1..100
  • keep_meta - 保留EXIF及其他元数据,默认为True
  • force_format - 强制调整大小后的图像格式,可用格式为pillow支持的格式,默认为None

谢谢你,斯蒂维。我会确保这样做。不过,我还没有成功地调整图像尺寸,这正是我想澄清的问题。在保存图像之前,我该如何调整它的尺寸呢?(我找到了ImageField的update_dimensions_fields类函数,但我无法弄清如何使用它) - rymanso
亲爱的Stevy,这很有道理 - 但是我仍然不清楚在哪里告诉Python我想要调整大小的img_width和img_height的目标值。抱歉打扰你了。 - rymanso
我会尽快回复您。谢谢。 - rymanso
ModuleNotFoundError: 找不到名为 'django_resized' 的模块 - Burakhan Aksoy
你是否使用 pip install django-resized 命令进行了安装? - Stevy

2
**

这个方法可行 首先,使用“pip install pillow”安装“PIL Fork”。

from PIL import Image


def __str__(self):
    return self.title


def save(self, *args, **kwargs):
    super(Posts, self).save(*args, **kwargs)
    imag = Image.open(self.post_image.path)
    if imag.width > 400 or imag.height> 300:
        output_size = (400, 300)
        imag.thumbnail(output_size)
        imag.save(self.post_image.path)
class Meta:
    verbose_name_plural = "Posts"

5
这不是一个答案。问题是“上传之前”。为了让你的东西起作用,整个文件仍然必须存在于服务器上,这意味着他们已经上传了他们的巨大图片。 - Chance

1

在保存图像之前,您可以使用此方法调整图像大小:(需要 pip install pillow

import os
from io import BytesIO
from PIL import Image as PilImage
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile

def resize_uploaded_image(image, max_width, max_height):
    size = (max_width, max_height)

    # Uploaded file is in memory
    if isinstance(image, InMemoryUploadedFile):
        memory_image = BytesIO(image.read())
        pil_image = PilImage.open(memory_image)
        img_format = os.path.splitext(image.name)[1][1:].upper()
        img_format = 'JPEG' if img_format == 'JPG' else img_format

        if pil_image.width > max_width or pil_image.height > max_height:
            pil_image.thumbnail(size)

        new_image = BytesIO()
        pil_image.save(new_image, format=img_format)

        new_image = ContentFile(new_image.getvalue())
        return InMemoryUploadedFile(new_image, None, image.name, image.content_type, None, None)

    # Uploaded file is in disk
    elif isinstance(image, TemporaryUploadedFile):
        path = image.temporary_file_path()
        pil_image = PilImage.open(path)

        if pil_image.width > max_width or pil_image.height > max_height:
            pil_image.thumbnail(size)
            pil_image.save(path)
            image.size = os.stat(path).st_size

    return image

然后在表单中图像字段的清理方法中使用它:

class ImageForm(forms.Form):
    IMAGE_WIDTH = 450
    IMAGE_HEIGHT = 450
    
    image = forms.ImageField()

    def clean_image(self):
        image = self.cleaned_data.get('image')
        image = resize_uploaded_image(image, self.IMAGE_WIDTH, self.IMAGE_HEIGHT)
        return image

为了理解resize_uploaded_image方法的工作原理,您可以阅读Django文档中有关上传文件处理的内容,这里这里

-1

你可以使用django-imagekit库。

安装

  1. 安装Pillow。(如果你在Django中使用ImageField,你应该已经完成了这个步骤。)
  2. pip install django-imagekit
  3. 'imagekit'添加到你的项目的settings.py文件中的INSTALLED_APPS列表中

Models.py

from django.db import models
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill

class Profile(models.Model):
    avatar = models.ImageField(upload_to='avatars')
    avatar_thumbnail = ImageSpecField(source='avatar',
                                  processors=[ResizeToFill(100, 50)],
                                  format='JPEG',
                                  options={'quality': 60})

请注意 ImageSpecFieldsource 属性,它指向实际的图像字段(在本例中为 avatar),因为 ImageSpecField 是虚拟的,您可以在 这里 阅读更多相关信息。

在模板中使用

<img src="{{ profile.avatar_thumbnail.url }}" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接