Изменение размера ImageField при сохранении и обновлении width_field и height_field - PullRequest
1 голос
/ 08 марта 2012

У меня есть модель, содержащая ImageField, размер которой должен быть изменен после загрузки.

class SomeModel(models.Model):
    banner = ImageField(upload_to='uploaded_images',
                        width_field='banner_width',
                        height_field='banner_height')
    banner_width = models.PositiveIntegerField(_('banner width'), editable=False)
    banner_height = models.PositiveIntegerField(_('banner height'), editable=False)

def save(self, *args, **kwargs):
    super(SomeModel, self).save(*args, **kwargs)
    resize_image(filename=self.banner.path,
                 width=MAX_BANNER_WIDTH,
                 height=MAX_BANNER_HEIGHT)

resize_image - это пользовательская функция, которая выполняет изменение размера, и все работает нормально, за исключением того, что banner_width и banner_height заполняются размерами исходного изображения перед изменением размера.

Фактический размер изображения с измененным размером может быть меньше заданных значений MAX, поэтому мне нужно открыть файл с измененным размером, чтобы проверить его фактические размеры после изменения размера. Затем я мог бы вручную установить banner_width и banner_height и снова сохранить, но это неэффективный способ. Я также мог бы сначала изменить размер, установить поля ширины и высоты, а затем сохранить, но файл в местоположении self.banner.path не существует до выполнения сохранения.

Любые предложения о том, как это должно быть сделано правильно?

1 Ответ

3 голосов
/ 28 марта 2012

После нескольких часов попыток сделать это эффективно, я изменил свой подход к этой проблеме и определил CustomImageField следующим образом:

class CustomImageField(ImageField):
    attr_class = CustomImageFieldFile

    def __init__(self, resize=False, to_width=None, to_height=None, force=True, *args, **kwargs):
        self.resize = resize
        if resize:
            self.to_width = to_width
            self.to_height = to_height
            self.force = force
        super(CustomImageField, self).__init__(*args, **kwargs)


class CustomImageFieldFile(ImageFieldFile): 

    def save(self, name, content, save=True):
        super(CustomImageFieldFile, self).save(name, content, save=save)
        if self.field.resize:
            resized_img = resize_image(filename=self.path,
                                       width=self.field.to_width,
                                       height=self.field.to_height,
                                       force=self.field.force)
            if resized_img:
                setattr(self.instance, self.field.width_field, resized_img.size[0])
                setattr(self.instance, self.field.height_field, resized_img.size[1])

Теперь я могу просто определить:

class SomeModel(models.Model):
    my_image = CustomImageField(resize=True, to_width=SOME_WIDTH, to_height=SOME_HEIGHT, force=False,
                                width_field='image_width', height_field='image_height')
    image_width = models.PositiveIntegerField(editable=False)
    image_height = models.PositiveIntegerField(editable=False)

И в зависимости от аргумента resize размер изображения может автоматически изменяться после загрузки, а поля ширины / высоты корректно обновляются без двойного сохранения объекта. После быстрых тестов все работает нормально.

...