I have a model containing ImageField
which should be resized after uploading.
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
is a custom function which does the resizing, and everything works fine, except that banner_width and banner_height are populated with dimensions of original image, before resizing.
Actual size of resized image may be smaller than MAX values given, so I have to open resized file to check it's actual dimensions after resizing. I could then manually set banner_width
and banner_height
, and save again, but it's not efficient way.
I could also do the resizing first, set width and height fields, and then save, but file at location self.banner.path
doesn't exist before save is performed.
Any suggestions on how should this be done properly?
After several hours of trying to do this efficiently, I've changed my approach to this problem and defined CustomImageField
like this:
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])
Now I can just define:
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)
And depending on resize
argument, image can be automatically resized after uploading, and width/height fields are correctly updated, without saving object twice. After quick tests it seems to be working fine.