mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-05-26 21:14:00 +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 ..receivers import configure_receivers
|
||||||
from ...base import ImageSpec
|
from ...base import ImageSpec
|
||||||
from ...utils import suggest_extension
|
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
|
The heart and soul of the ImageKit library, ImageSpecField allows you to add
|
||||||
variants of uploaded images to your models.
|
variants of uploaded images to your models.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, processors=None, format=None, options=None,
|
def __init__(self, processors=None, format=None, options=None,
|
||||||
image_field=None, storage=None, autoconvert=True,
|
image_field=None, storage=None, autoconvert=None,
|
||||||
image_cache_backend=None, image_cache_strategy=None):
|
image_cache_backend=None, image_cache_strategy=None, spec=None,
|
||||||
|
id=None):
|
||||||
|
|
||||||
# The spec accepts a callable value for processors, but it
|
# The spec accepts a callable value for processors, but it
|
||||||
# takes different arguments than the callable that ImageSpecField
|
# takes different arguments than the callable that ImageSpecField
|
||||||
# expects, so we create a partial application and pass that instead.
|
# 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.
|
# 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 \
|
p = lambda file: processors(instance=file.instance,
|
||||||
callable(processors) else processors
|
file=file) if callable(processors) else processors
|
||||||
|
|
||||||
self.spec = ImageSpec(
|
SpecHost.__init__(self, processors=p, format=format,
|
||||||
processors=p,
|
options=options, storage=storage, autoconvert=autoconvert,
|
||||||
format=format,
|
image_cache_backend=image_cache_backend,
|
||||||
options=options,
|
image_cache_strategy=image_cache_strategy, spec=spec, id=id)
|
||||||
storage=storage,
|
|
||||||
autoconvert=autoconvert,
|
|
||||||
image_cache_backend=image_cache_backend,
|
|
||||||
image_cache_strategy=image_cache_strategy,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.image_field = image_field
|
self.image_field = image_field
|
||||||
|
|
||||||
|
|
@ -59,6 +56,16 @@ class ImageSpecField(object):
|
||||||
setattr(cls, '_ik', ik)
|
setattr(cls, '_ik', ik)
|
||||||
ik.spec_fields.append(name)
|
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
|
# Register the field with the image_cache_backend
|
||||||
try:
|
try:
|
||||||
self.spec.image_cache_backend.register_field(cls, self, name)
|
self.spec.image_cache_backend.register_field(cls, self, name)
|
||||||
|
|
|
||||||
|
|
@ -164,3 +164,61 @@ class ImageSpec(BaseImageSpec):
|
||||||
storage.save(filename, content)
|
storage.save(filename, content)
|
||||||
|
|
||||||
return 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