mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-17 05:40:25 +00:00
Back ImageSpecFields with spec registry
This marks a major step towards centralizing some of the "spec" logic and creating a single access point for them. Because `ImageSpecFields` are just alternative interfaces for defining and registering specs, they can be accessed and overridden in the same manner as other specs (like those used by template tags): via the spec registry.
This commit is contained in:
parent
99ba61d605
commit
f289ff3199
2 changed files with 79 additions and 14 deletions
|
|
@ -8,34 +8,31 @@ from .utils import ImageSpecFileDescriptor, ImageKitMeta
|
|||
from ..receivers import configure_receivers
|
||||
from ...base import ImageSpec
|
||||
from ...utils import suggest_extension
|
||||
from ...specs import SpecHost
|
||||
|
||||
|
||||
class ImageSpecField(object):
|
||||
class ImageSpecField(SpecHost):
|
||||
"""
|
||||
The heart and soul of the ImageKit library, ImageSpecField allows you to add
|
||||
variants of uploaded images to your models.
|
||||
|
||||
"""
|
||||
def __init__(self, processors=None, format=None, options=None,
|
||||
image_field=None, storage=None, autoconvert=True,
|
||||
image_cache_backend=None, image_cache_strategy=None):
|
||||
image_field=None, storage=None, autoconvert=None,
|
||||
image_cache_backend=None, image_cache_strategy=None, spec=None,
|
||||
id=None):
|
||||
|
||||
# The spec accepts a callable value for processors, but it
|
||||
# takes different arguments than the callable that ImageSpecField
|
||||
# expects, so we create a partial application and pass that instead.
|
||||
# TODO: Should we change the signatures to match? Even if `instance` is not part of the signature, it's accessible through the source file object's instance property.
|
||||
p = lambda file: processors(instance=file.instance, file=file) if \
|
||||
callable(processors) else processors
|
||||
p = lambda file: processors(instance=file.instance,
|
||||
file=file) if callable(processors) else processors
|
||||
|
||||
self.spec = ImageSpec(
|
||||
processors=p,
|
||||
format=format,
|
||||
options=options,
|
||||
storage=storage,
|
||||
autoconvert=autoconvert,
|
||||
image_cache_backend=image_cache_backend,
|
||||
image_cache_strategy=image_cache_strategy,
|
||||
)
|
||||
SpecHost.__init__(self, processors=p, format=format,
|
||||
options=options, storage=storage, autoconvert=autoconvert,
|
||||
image_cache_backend=image_cache_backend,
|
||||
image_cache_strategy=image_cache_strategy, spec=spec, id=id)
|
||||
|
||||
self.image_field = image_field
|
||||
|
||||
|
|
@ -59,6 +56,16 @@ class ImageSpecField(object):
|
|||
setattr(cls, '_ik', ik)
|
||||
ik.spec_fields.append(name)
|
||||
|
||||
# Generate a spec_id to register the spec with. The default spec id is
|
||||
# "<app>:<model>_<field>"
|
||||
if not self.spec_id:
|
||||
self.spec_id = (u'%s:%s_%s' % (cls._meta.app_label,
|
||||
cls._meta.object_name, name)).lower()
|
||||
|
||||
# Register the spec with the id. This allows specs to be overridden
|
||||
# later, from outside of the model definition.
|
||||
self.register_spec(self.spec_id)
|
||||
|
||||
# Register the field with the image_cache_backend
|
||||
try:
|
||||
self.spec.image_cache_backend.register_field(cls, self, name)
|
||||
|
|
|
|||
|
|
@ -164,3 +164,61 @@ class ImageSpec(BaseImageSpec):
|
|||
storage.save(filename, content)
|
||||
|
||||
return content
|
||||
|
||||
|
||||
class SpecHost(object):
|
||||
"""
|
||||
An object that ostensibly has a spec attribute but really delegates to the
|
||||
spec registry.
|
||||
|
||||
"""
|
||||
def __init__(self, processors=None, format=None, options=None,
|
||||
storage=None, autoconvert=None, image_cache_backend=None,
|
||||
image_cache_strategy=None, spec=None, id=None):
|
||||
|
||||
if spec:
|
||||
if any([processors, format, options, storage, autoconvert,
|
||||
image_cache_backend, image_cache_strategy]):
|
||||
raise TypeError('You can provide either an image spec or'
|
||||
' arguments for the ImageSpec constructor, but not both.')
|
||||
else:
|
||||
spec = ImageSpec(
|
||||
processors=processors,
|
||||
format=format,
|
||||
options=options,
|
||||
storage=storage,
|
||||
autoconvert=autoconvert,
|
||||
image_cache_backend=image_cache_backend,
|
||||
image_cache_strategy=image_cache_strategy,
|
||||
)
|
||||
|
||||
self._original_spec = spec
|
||||
self.spec_id = None
|
||||
|
||||
if id:
|
||||
# If an id is given, register the spec immediately.
|
||||
self.register_spec(id)
|
||||
|
||||
def register_spec(self, id):
|
||||
"""
|
||||
Registers the spec with the specified id. Useful for when the id isn't
|
||||
known when the instance is constructed (e.g. for ImageSpecFields whose
|
||||
generated `spec_id`s are only known when they are contributed to a
|
||||
class)
|
||||
|
||||
"""
|
||||
self.spec_id = id
|
||||
spec_registry.register(id, self._original_spec)
|
||||
|
||||
@property
|
||||
def spec(self):
|
||||
"""
|
||||
Look up the spec by the spec id. We do this (instead of storing the
|
||||
spec as an attribute) so that users can override apps' specs--without
|
||||
having to edit model definitions--simply by registering another spec
|
||||
with the same id.
|
||||
|
||||
"""
|
||||
if not getattr(self, 'spec_id', None):
|
||||
raise Exception('Object %s has no spec id.' % self)
|
||||
return spec_registry.get_spec(self.spec_id)
|
||||
|
|
|
|||
Loading…
Reference in a new issue