From 754f9ae6f56b85cbeed818488ea7966f7c5c8fa4 Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 4 Jun 2014 09:38:13 +0700 Subject: [PATCH] First stab at deleting file on update --- thumbnails/fields.py | 12 +++++++++++ thumbnails/files.py | 3 +++ thumbnails/tests/models.py | 2 +- thumbnails/tests/test_fields.py | 36 ++++++++++++++++++++++++++++----- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/thumbnails/fields.py b/thumbnails/fields.py index 870bed9..79caab5 100644 --- a/thumbnails/fields.py +++ b/thumbnails/fields.py @@ -16,6 +16,7 @@ def __init__(self, *args, **kwargs): if kwargs.get('storage'): raise ValueError('Please define storage backend in settings.py instead on the field itself') kwargs['storage'] = storage.get_backend() + self.delete_on_update = kwargs.pop('delete_on_update', False) self.metadata_backend = metadata.get_backend() super(ImageField, self).__init__(*args, **kwargs) @@ -28,7 +29,18 @@ def pre_save(self, model_instance, add): """ file = getattr(model_instance, self.attname) + # new file is assigned if file and not file._committed: + # detect if there are old file needs to be cleaned + old_file = getattr(type(model_instance).objects.get(id=model_instance.id), + self.attname) + + if old_file: + all_thumbs = [thumb for thumb in old_file.thumbnails.all()] + for thumb_size in all_thumbs: + old_file.thumbnails.delete(thumb_size) + old_file.delete() + image_file = file if self.resize_source_to: file.seek(0) diff --git a/thumbnails/files.py b/thumbnails/files.py index c31629a..ffe5d47 100644 --- a/thumbnails/files.py +++ b/thumbnails/files.py @@ -28,6 +28,9 @@ def save(self, name, content, save=True): self.metadata_backend.add_source(self.name) return thumbnail + def delete(self, save=True): + super(ThumbnailedImageFile, self).delete(save) + class ThumbnailManager(object): """A class that manages creation and retrieval of thumbnails.""" diff --git a/thumbnails/tests/models.py b/thumbnails/tests/models.py index b0bd045..14a3ba4 100644 --- a/thumbnails/tests/models.py +++ b/thumbnails/tests/models.py @@ -4,5 +4,5 @@ class TestModel(models.Model): - avatar = ImageField(upload_to='avatars', resize_source_to='source') + avatar = ImageField(upload_to='avatars', resize_source_to='source', delete_on_update=True) profile_picture = ImageField(upload_to='avatars', blank=True, null=True, resize_source_to='source') diff --git a/thumbnails/tests/test_fields.py b/thumbnails/tests/test_fields.py index 7483e20..e46514d 100644 --- a/thumbnails/tests/test_fields.py +++ b/thumbnails/tests/test_fields.py @@ -17,7 +17,10 @@ def setUp(self): with open('thumbnails/tests/tests.png', 'rb') as image_file: self.instance.avatar = File(image_file) self.instance.save() + self.avatar_folder = \ + os.path.join(self.instance.avatar.storage.temporary_location, 'avatars') + self.avatar_thumb_folder = \ os.path.join(self.instance.avatar.storage.temporary_location, conf.BASE_DIR, 'avatars') self.basename = os.path.basename(self.instance.avatar.path) self.filename, self.ext = os.path.splitext(self.basename) @@ -29,9 +32,9 @@ def tearDown(self): def test_image_field(self): # 1. Test for thumbnail creation - self.assertFalse(os.path.isfile(os.path.join(self.avatar_folder, self.filename + '_small' + self.ext))) + self.assertFalse(os.path.isfile(os.path.join(self.avatar_thumb_folder, self.filename + '_small' + self.ext))) thumb = self.instance.avatar.thumbnails.create(size='small') - self.assertTrue(os.path.isfile(os.path.join(self.avatar_folder, self.filename + '_small' + self.ext))) + self.assertTrue(os.path.isfile(os.path.join(self.avatar_thumb_folder, self.filename + '_small' + self.ext))) # Make sure the returned thumbnail is of thumbnail class, not metadata self.assertTrue(isinstance(thumb, Thumbnail)) @@ -39,9 +42,9 @@ def test_image_field(self): self.assertEqual(thumb, self.instance.avatar.thumbnails.get(size='small')) # 3. Test for thumbnail deletion - self.assertTrue(os.path.isfile(os.path.join(self.avatar_folder, self.filename + '_small' + self.ext))) + self.assertTrue(os.path.isfile(os.path.join(self.avatar_thumb_folder, self.filename + '_small' + self.ext))) self.instance.avatar.thumbnails.delete(size='small') - self.assertFalse(os.path.isfile(os.path.join(self.avatar_folder, self.filename + '_small' + self.ext))) + self.assertFalse(os.path.isfile(os.path.join(self.avatar_thumb_folder, self.filename + '_small' + self.ext))) def test_thumbnail_field(self): # Make sure ThumbnailManager return the correct thumbnail @@ -58,7 +61,7 @@ def test_thumbnail_field(self): # Test for name clashing with another file with the same name self.instance.avatar.thumbnails.delete('large') - open(os.path.join(self.avatar_folder, 'tests_large.png'), 'w').close() + open(os.path.join(self.avatar_thumb_folder, 'tests_large.png'), 'w').close() self.instance.avatar.thumbnails.create('large') # Due to uuid4 for file name, this should not clash @@ -142,3 +145,26 @@ def test_resize_source_to_none(self): with open('thumbnails/tests/tests.png', 'rb') as image_file: self.instance.profile_picture = File(image_file) self.instance.save() + + def test_delete_on_update(self): + # create thumbnails + sanity check for file existence + self.instance.avatar.thumbnails.large + self.instance.avatar.thumbnails.small + + original_file = os.path.join(self.avatar_folder, self.filename + self.ext) + small_thumb = os.path.join(self.avatar_thumb_folder, self.filename + '_small' + self.ext) + large_thumb = os.path.join(self.avatar_thumb_folder, self.filename + '_large' + self.ext) + + self.assertTrue(os.path.isfile(original_file)) + self.assertTrue(os.path.isfile(small_thumb)) + self.assertTrue(os.path.isfile(large_thumb)) + + # if file is updated + with open('thumbnails/tests/tests.png', 'rb') as image_file: + self.instance.avatar = File(image_file) + self.instance.save() + + # make sure all old files are deleted + self.assertFalse(os.path.isfile(original_file)) + self.assertFalse(os.path.isfile(small_thumb)) + self.assertFalse(os.path.isfile(large_thumb))