Merge pull request #114 from cyberdelia/cache-backends

Add celery backend and separate backends.
This commit is contained in:
Bryan Veloso 2012-03-15 12:46:07 -07:00
commit f54ff8796e
3 changed files with 78 additions and 31 deletions

View file

@ -0,0 +1,33 @@
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
from imagekit.imagecache.base import InvalidImageCacheBackendError, PessimisticImageCacheBackend, NonValidatingImageCacheBackend
_default_image_cache_backend = None
def get_default_image_cache_backend():
"""
Get the default image cache backend. Uses the same method as
django.core.file.storage.get_storage_class
"""
global _default_image_cache_backend
if not _default_image_cache_backend:
from ..settings import DEFAULT_IMAGE_CACHE_BACKEND as import_path
try:
dot = import_path.rindex('.')
except ValueError:
raise ImproperlyConfigured("%s isn't an image cache backend module." % \
import_path)
module, classname = import_path[:dot], import_path[dot + 1:]
try:
mod = import_module(module)
except ImportError, e:
raise ImproperlyConfigured('Error importing image cache backend module %s: "%s"' % (module, e))
try:
cls = getattr(mod, classname)
_default_image_cache_backend = cls()
except AttributeError:
raise ImproperlyConfigured('Image cache backend module "%s" does not define a "%s" class.' % (module, classname))
return _default_image_cache_backend

View file

@ -1,5 +1,8 @@
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
class InvalidImageCacheBackendError(ImproperlyConfigured):
pass
class PessimisticImageCacheBackend(object):
@ -55,33 +58,3 @@ class NonValidatingImageCacheBackend(object):
def clear(self, file):
file.delete(save=False)
_default_image_cache_backend = None
def get_default_image_cache_backend():
"""
Get the default image cache backend. Uses the same method as
django.core.file.storage.get_storage_class
"""
global _default_image_cache_backend
if not _default_image_cache_backend:
from .settings import DEFAULT_IMAGE_CACHE_BACKEND as import_path
try:
dot = import_path.rindex('.')
except ValueError:
raise ImproperlyConfigured("%s isn't an image cache backend module." % \
import_path)
module, classname = import_path[:dot], import_path[dot + 1:]
try:
mod = import_module(module)
except ImportError, e:
raise ImproperlyConfigured('Error importing image cache backend module %s: "%s"' % (module, e))
try:
cls = getattr(mod, classname)
_default_image_cache_backend = cls()
except AttributeError:
raise ImproperlyConfigured('Image cache backend module "%s" does not define a "%s" class.' % (module, classname))
return _default_image_cache_backend

View file

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from imagekit.imagecache import PessimisticImageCacheBackend, InvalidImageCacheBackendError
def generate(model, pk, attr):
try:
instance = model._default_manager.get(pk=pk)
except model.DoesNotExist:
pass # The model was deleted since the task was scheduled. NEVER MIND!
else:
getattr(instance, attr).generate(save=True)
class CeleryImageCacheBackend(PessimisticImageCacheBackend):
"""
A pessimistic cache state backend that uses celery to generate its spec
images. Like PessimisticCacheStateBackend, this one checks to see if the
file exists on validation, so the storage is hit fairly frequently, but an
image is guaranteed to exist. However, while validation guarantees the
existence of *an* image, it does not necessarily guarantee that you will get
the correct image, as the spec may be pending regeneration. In other words,
while there are `generate` tasks in the queue, it is possible to get a
stale spec image. The tradeoff is that calling `invalidate()` won't block
to interact with file storage.
"""
def __init__(self):
try:
from celery.task import task
except:
raise InvalidImageCacheBackendError("Celery image cache backend requires either the 'celery' library")
if not getattr(CeleryImageCacheBackend, '_task', None):
CeleryImageCacheBackend._task = task(generate)
def invalidate(self, file):
self._task.delay(file.instance.__class__, file.instance.pk, file.attname)
def clear(self, file):
file.delete(save=False)