django-imagekit: How to cleanup cache backend and remove generated thumbnails from storage ¶
Best effort to regenerate the thumbnail when the associated image is updated
In a django Model, I keep an ImageField "image" and an associated "thumbnail", based on from imagekit.models.ImageSpecField.
I might need to rebuild the image, keeping the same filename for the bitmap.
Obviously, the thumbnail needs to be updated as well; my first attempt was:
self.thumbnail.generate(force=True)
but that's not enough; despite the force=True parameter, the thumbnail remains unchanged.
After some trials and errors, I ended up with the following workaround:
class MyModel(model.Model): ... image = models.ImageField(_('Image'), null=True, blank=True, upload_to=get_acquisition_media_file_path) thumbnail = ImageSpecField(source='image', processors=[ResizeToFill(200, 100)], format='PNG') ... def save_image_from_data(self): # Create a new random image from random import randint rgb = (randint(0, 255), randint(0, 255), randint(0, 255)) image_size = (200, 200) image = PILImage.new('RGB', image_size, rgb) with io.BytesIO() as output: image.save(output, format="PNG") contents = output.getvalue() # Best effort to remove the thumbnail, if any try: file = self.thumbnail.file #except FileNotFoundError: except: pass try: cache_backend = self.thumbnail.cachefile_backend cache_backend.cache.delete(cache_backend.get_key(file)) #self.thumbnail.storage.delete(file) self.thumbnail.storage.delete(file.name) except: pass # Save image self.image = ContentFile(contents, "acquisition_%d.png" % self.position) self.save() # Regenerate thumbnail self.thumbnail.generate(force=True) return True
Thumbnails cleanup
ImageKit has a bug where files are cached and not deleted right away:
https://github.com/matthewwithanm/django-imagekit/issues/229#issuecomment-315690575
An interesting solution to the is the following.
UNTESTED: I didn't try this yet in a real situation
from django.db.models.signals import post_delete @staticmethod def post_delete(sender, instance, **kwargs): for field in ['thumbnail', ]: field = getattr(instance, field) try: file = field.file except FileNotFoundError: pass else: cache_backend = field.cachefile_backend cache_backend.cache.delete(cache_backend.get_key(file)) field.storage.delete(file) instance.file.delete(save=False) post_delete.connect(MyModel.post_delete, sender=MyModel)
References
Manually clear the cache
because in ImageKit 4.0 django cache backend is configured to preserve the state of images forever then you need to clear it also.
from imagekit.utils import get_cache get_cache().clear()
which just runs "FLUSHDB" on Redis !