diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index c9106df..4a4dc8c --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ In your `settings.py` add an option called `THUMBNAIL_OPTIONS_DICT`, defining al } } +Or you can also define class variable `THUMBNAIL_OPTIONS_DICT` in the model for thumbnails on model basis (see example below). This takes precedence over global settings. + In your models, use `thumbnail.models.AsyncThumbnailMixin` as a baseclass. Make sure that your model inherits from AsyncThumbnailMixin first. This will call celery task on save(), and create one or more thumbnails from the specified image field. Use class variable `image_field_name` to configure the field that @@ -51,8 +53,14 @@ Example: class Book(AsyncThumbnailMixin, models.Model): image_field_name = 'cover_image' + THUMBNAIL_OPTIONS_DICT = { + 'small': { + 'geometry': '140x140', + 'crop': 'center' + } + } - title = models.CharField(blank=False, max_length=255, db_index=True) + title = models.CharField(blank=False, max_length=255, db_index=True) cover_image = thumbnail.ImageField(upload_to='books/') In templates: diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 diff --git a/thumbnail/__init__.py b/thumbnail/__init__.py old mode 100644 new mode 100755 index c3f86ec..99af296 --- a/thumbnail/__init__.py +++ b/thumbnail/__init__.py @@ -9,8 +9,9 @@ def get_thumbnail(file_, name): """ get_thumbnail version that uses aliasses defined in THUMBNAIL_OPTIONS_DICT """ - options = settings.OPTIONS_DICT[name] + options_dict = getattr(file_.instance, 'THUMBNAIL_OPTIONS_DICT', settings.OPTIONS_DICT) + options = options_dict[name] opt = copy(options) geometry = opt.pop('geometry') - return original_get_thumbnail(file_, geometry, **opt) \ No newline at end of file + return original_get_thumbnail(file_, geometry, **opt) diff --git a/thumbnail/backend.py b/thumbnail/backend.py old mode 100644 new mode 100755 diff --git a/thumbnail/conf/__init__.py b/thumbnail/conf/__init__.py old mode 100644 new mode 100755 diff --git a/thumbnail/conf/settings.py b/thumbnail/conf/settings.py old mode 100644 new mode 100755 index 979b781..b1b7ec2 --- a/thumbnail/conf/settings.py +++ b/thumbnail/conf/settings.py @@ -11,4 +11,5 @@ 'crop': 'center' } } -OPTIONS_DICT = getattr(settings, 'THUMBNAIL_OPTIONS_DICT', DEFAULT_OPTIONS_DICT) \ No newline at end of file +OPTIONS_DICT = getattr(settings, 'THUMBNAIL_OPTIONS_DICT', DEFAULT_OPTIONS_DICT) +SAVE_MODEL = getattr(settings, 'THUMBNAIL_SAVE_MODEL', True) diff --git a/thumbnail/models.py b/thumbnail/models.py old mode 100644 new mode 100755 index c7cabb6..9572a96 --- a/thumbnail/models.py +++ b/thumbnail/models.py @@ -12,11 +12,14 @@ class AsyncThumbnailMixin(object): image_field_name = 'picture' def call_upload_task(self): - for name, options in settings.OPTIONS_DICT.items(): + options_dict = getattr(self, 'THUMBNAIL_OPTIONS_DICT', settings.OPTIONS_DICT) + for name, options in options_dict.items(): opt = copy(options) geometry = opt.pop('geometry') - create_thumbnail.delay(getattr(self, self.image_field_name), geometry, **opt) + create_thumbnail.delay(self, getattr(self, self.image_field_name), geometry, **opt) def save(self, *args, **kwargs): + thumbnail_task_completed = kwargs.pop('thumbnail_task_completed', False) super(AsyncThumbnailMixin, self).save(*args, **kwargs) - self.call_upload_task() + if not thumbnail_task_completed: + self.call_upload_task() diff --git a/thumbnail/tasks.py b/thumbnail/tasks.py old mode 100644 new mode 100755 index fe5b2e3..e1a949f --- a/thumbnail/tasks.py +++ b/thumbnail/tasks.py @@ -1,23 +1,13 @@ import celery from sorl.thumbnail import default -from sorl.thumbnail.images import ImageFile -@celery.task -def create_thumbnail(image_file, geometry_string, **options): - # Note that thumbnail options must be same for a type of thumbnail. - # Otherwise, different thumbnails are created. - source = ImageFile(image_file) - for key, value in default.backend.default_options.items(): - options.setdefault(key, value) - name = default.backend._get_thumbnail_filename(source, geometry_string, options) - thumbnail = ImageFile(name, default.storage) - source_image = default.engine.get_image(source) - default.backend._create_thumbnail(source_image, geometry_string, options, thumbnail) +from .conf import settings - # Need to set size to store in kvstore. - size = default.engine.get_image_size(source_image) - source.set_size(size) - default.kvstore.get_or_set(source) - default.kvstore.set(thumbnail, source) \ No newline at end of file +@celery.task +def create_thumbnail(model, image_file, geometry_string, **options): + # Simply call get_thumbnail, if thumbnail does not exist sorl will create it + default.backend.get_thumbnail(image_file, geometry_string, **options) + if settings.SAVE_MODEL: + model.save(thumbnail_task_completed=True) # helful for signaling haystack to update index diff --git a/thumbnail/templatetags/__init__.py b/thumbnail/templatetags/__init__.py old mode 100644 new mode 100755 diff --git a/thumbnail/templatetags/thumbnail_tags.py b/thumbnail/templatetags/thumbnail_tags.py old mode 100644 new mode 100755 index 9b4ac1e..bcc3029 --- a/thumbnail/templatetags/thumbnail_tags.py +++ b/thumbnail/templatetags/thumbnail_tags.py @@ -16,27 +16,37 @@ class CustomThumbnailNode(ThumbnailNode): """ Extends ThumbnailNode to use thumbnail sizes from settings""" error_message = ('Please enter sizes defined in settings') def __init__(self, parser, token): + self.parser = parser + self.token = token ThumbnailNode.__init__(self, parser, token) - bits = token.split_contents() + + def pre_render(self, context): + file_ = self.file_.resolve(context) + bits = self.token.split_contents() if len(bits) < 5 or bits[-2] != 'as': raise TemplateSyntaxError(self.error_msg) try: - thumbnail_settings = get_thumbnail_options_from_dict(settings.OPTIONS_DICT) + thumbnail_settings = get_thumbnail_options_from_dict( + getattr(file_.instance, 'THUMBNAIL_OPTIONS_DICT', settings.OPTIONS_DICT)) thumbnail_options = thumbnail_settings[bits[2]] thumbnail_options = thumbnail_options.split() except KeyError: raise TemplateSyntaxError(self.error_message) - self.geometry = parser.compile_filter("'%s'" % thumbnail_options[0]) + self.geometry = self.parser.compile_filter("'%s'" % thumbnail_options[0]) self.options = [] try: m = kw_pat.match(thumbnail_options[1]) key = smart_str(m.group('key')) - expr = parser.compile_filter('"%s"' % m.group('value')) + expr = self.parser.compile_filter('"%s"' % m.group('value')) self.options.append((key, expr)) except IndexError: pass self.as_var = bits[-1] + + def _render(self, context): + self.pre_render(context) + return ThumbnailNode._render(self, context) @register.tag def thumbnail(parser, token): - return CustomThumbnailNode(parser, token) \ No newline at end of file + return CustomThumbnailNode(parser, token) diff --git a/thumbnail/utils.py b/thumbnail/utils.py old mode 100644 new mode 100755