mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-16 21:30:23 +00:00
Split before_access into two signals
Differentiating between when the generated file content is required and when the generated file is just required to exist gives us more flexibility with strategies.
This commit is contained in:
parent
6db082bca2
commit
c89b18aa95
6 changed files with 64 additions and 18 deletions
|
|
@ -35,18 +35,25 @@ Cache File Strategy
|
|||
Each ``ImageCacheFile`` has a cache file strategy, which abstracts away when
|
||||
image is actually generated. It can implement the following four methods:
|
||||
|
||||
* ``before_access`` - called by ``ImageCacheFile`` when you access its url,
|
||||
width, or height attribute.
|
||||
* ``on_content_required`` - called by ``ImageCacheFile`` when it requires the
|
||||
contents of the generated image. For example, when you call ``read()`` or
|
||||
try to access information contained in the file.
|
||||
* ``on_existence_required`` - called by ``ImageCacheFile`` when it requires the
|
||||
generated image to exist but may not be concerned with its contents. For
|
||||
example, when you access its ``url`` or ``path`` attribute.
|
||||
* ``on_source_created`` - called when the source of a spec is created
|
||||
* ``on_source_changed`` - called when the source of a spec is changed
|
||||
* ``on_source_deleted`` - called when the source of a spec is deleted
|
||||
|
||||
The default strategy only defines the first of these, as follows:
|
||||
The default strategy only defines the first two of these, as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class JustInTime(object):
|
||||
def before_access(self, file):
|
||||
def on_content_required(self, file):
|
||||
file.generate()
|
||||
|
||||
def on_existence_required(self, file):
|
||||
file.generate()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from django.core.files.images import ImageFile
|
|||
from django.utils.functional import LazyObject
|
||||
from ..files import BaseIKFile
|
||||
from ..registry import generator_registry
|
||||
from ..signals import before_access
|
||||
from ..signals import content_required, existence_required
|
||||
from ..utils import get_logger, get_singleton, generate, get_by_qname
|
||||
|
||||
|
||||
|
|
@ -57,7 +57,30 @@ class ImageCacheFile(BaseIKFile, ImageFile):
|
|||
|
||||
def _require_file(self):
|
||||
if not getattr(self, '_file', None):
|
||||
before_access.send(sender=self, file=self)
|
||||
content_required.send(sender=self, file=self)
|
||||
self._file = self.storage.open(self.name, 'rb')
|
||||
|
||||
# The ``path`` and ``url`` properties are overridden so as to not call
|
||||
# ``_require_file``, which is only meant to be called when the file object
|
||||
# will be directly interacted with (e.g. when using ``read()``). These only
|
||||
# require the file to exist; they do not need its contents to work. This
|
||||
# distinction gives the user the flexibility to create a cache file
|
||||
# strategy that assumes the existence of a file, but can still make the file
|
||||
# available when its contents are required.
|
||||
|
||||
def _storage_attr(self, attr):
|
||||
if not getattr(self, '_file', None):
|
||||
existence_required.send(sender=self, file=self)
|
||||
fn = getattr(self.storage, attr)
|
||||
return fn(self.name)
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self._storage_attr('path')
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return self._storage_attr('url')
|
||||
|
||||
def generate(self, force=False):
|
||||
"""
|
||||
|
|
@ -101,9 +124,9 @@ class ImageCacheFile(BaseIKFile, ImageFile):
|
|||
if not self.name:
|
||||
return False
|
||||
|
||||
# Dispatch the before_access signal before checking to see if the file
|
||||
# exists. This gives the strategy a chance to create the file.
|
||||
before_access.send(sender=self, file=self)
|
||||
# Dispatch the existence_required signal before checking to see if the
|
||||
# file exists. This gives the strategy a chance to create the file.
|
||||
existence_required.send(sender=self, file=self)
|
||||
return self.cachefile_backend.exists(self)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ class JustInTime(object):
|
|||
|
||||
"""
|
||||
|
||||
def before_access(self, file):
|
||||
def on_existence_required(self, file):
|
||||
file.generate()
|
||||
|
||||
def on_content_required(self, file):
|
||||
file.generate()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from .exceptions import AlreadyRegistered, NotRegistered
|
||||
from .signals import before_access, source_created, source_changed, source_deleted
|
||||
from .signals import (content_required, existence_required, source_created,
|
||||
source_changed, source_deleted)
|
||||
from .utils import call_strategy_method
|
||||
|
||||
|
||||
|
|
@ -12,7 +13,8 @@ class GeneratorRegistry(object):
|
|||
"""
|
||||
def __init__(self):
|
||||
self._generators = {}
|
||||
before_access.connect(self.before_access_receiver)
|
||||
content_required.connect(self.content_required_receiver)
|
||||
existence_required.connect(self.existence_required_receiver)
|
||||
|
||||
def register(self, id, generator):
|
||||
registered_generator = self._generators.get(id)
|
||||
|
|
@ -42,13 +44,19 @@ class GeneratorRegistry(object):
|
|||
def get_ids(self):
|
||||
return self._generators.keys()
|
||||
|
||||
def before_access_receiver(self, sender, file, **kwargs):
|
||||
def content_required_receiver(self, sender, file, **kwargs):
|
||||
self._receive(file, 'on_content_required')
|
||||
|
||||
def existence_required_receiver(self, sender, file, **kwargs):
|
||||
self._receive(file, 'on_existence_required')
|
||||
|
||||
def _receive(self, file, callback):
|
||||
generator = file.generator
|
||||
|
||||
# FIXME: I guess this means you can't register functions?
|
||||
if generator.__class__ in self._generators.values():
|
||||
# Only invoke the strategy method for registered generators.
|
||||
call_strategy_method(file, 'before_access')
|
||||
call_strategy_method(file, callback)
|
||||
|
||||
|
||||
class SourceGroupRegistry(object):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ from django.dispatch import Signal
|
|||
|
||||
|
||||
# Generated file signals
|
||||
before_access = Signal()
|
||||
content_required = Signal()
|
||||
existence_required = Signal()
|
||||
|
||||
# Source group signals
|
||||
source_created = Signal()
|
||||
|
|
|
|||
|
|
@ -29,12 +29,16 @@ class ProcessedImageFieldModel(models.Model):
|
|||
|
||||
class CountingCacheFileStrategy(object):
|
||||
def __init__(self):
|
||||
self.before_access_count = 0
|
||||
self.on_existence_required_count = 0
|
||||
self.on_content_required_count = 0
|
||||
self.on_source_changed_count = 0
|
||||
self.on_source_created_count = 0
|
||||
|
||||
def before_access(self, file):
|
||||
self.before_access_count += 1
|
||||
def on_existence_required(self, file):
|
||||
self.on_existence_required_count += 1
|
||||
|
||||
def on_content_required(self, file):
|
||||
self.on_content_required_count += 1
|
||||
|
||||
def on_source_changed(self, file):
|
||||
self.on_source_changed_count += 1
|
||||
|
|
|
|||
Loading…
Reference in a new issue