如何在Django的ImageField保存前获取其内容?

5 投票
3 回答
4949 浏览
提问于 2025-04-17 09:46

我正在尝试在保存我的模型实例时调整一张图片的大小。

class Picture(models.Model):
  image_file = models.ImageField(upload_to="pictures")
  thumb_file = models.ImageField(upload_to="pictures", editable=False)
  def save(self, force_insert=False, force_update=False):
    image_object = Image.open(self.image_file.path)
    #[...] nothing yet
    super(Picture, self).save(force_insert, force_update)

问题是,在模型保存之前,self.image_file.path 这个路径并不存在。虽然它返回了一个正确的路径,但图片还没有生成。因此,我无法在PIL中打开它进行调整大小。

我想把缩略图存储在 thumb_file(另一个 ImageField)中,所以我需要在保存模型之前进行处理。

有没有什么好的方法可以打开这个文件(也许在内存中获取临时的图片对象),还是说我必须先保存整个模型,然后再调整大小,最后再保存一次?

3 个回答

0

在你的模型的 save 方法中,字段的值会是一个有效的 FileField 或者在 ImageField 的情况下是 ImageFileField。这个 Django 类实现了文件对象的接口(也就是 readwrite 方法),而且在文件还没有保存到你的模型之前就可以使用,所以你可以把它作为参数传给 PIL.Image.open

class Picture(models.Model):
    image_file = models.ImageField(upload_to="pictures")
    thumb_file = models.ImageField(upload_to="pictures", editable=False)

    def save(self, force_insert=False, force_update=False):
        img = Image.open(self.image_file)
        # work with img, is an Image object
        super(Picture, self).save(force_insert, force_update)

这个功能在 Django 版本 >= 1.5 中是可以用的。

0

也许你可以直接打开文件,然后把得到的文件句柄传给 Image.open

image_object = Image.open(self.image_file.open())

抱歉,我现在无法测试这个。

1

我使用了这个代码片段

import Image

def fit(file_path, max_width=None, max_height=None, save_as=None):
    # Open file
    img = Image.open(file_path)

    # Store original image width and height
    w, h = img.size

    # Replace width and height by the maximum values
    w = int(max_width or w)
    h = int(max_height or h)

    # Proportinally resize
    img.thumbnail((w, h), Image.ANTIALIAS)

    # Save in (optional) 'save_as' or in the original path
    img.save(save_as or file_path)

    return True

然后在模型中:

def save(self, *args, **kwargs):
    super(Picture, self).save(*args, **kwargs)
    if self.image:
        fit(self.image_file.path, settings.MAX_WIDTH, settings.MAX_HEIGHT)

撰写回答