django-imagekit/imagekit/models/fields/__init__.py

106 lines
4.2 KiB
Python

from django.db import models
from .files import ProcessedImageFieldFile
from .utils import ImageSpecFileDescriptor
from ...specs import SpecHost
from ...specs.sourcegroups import ImageFieldSourceGroup
from ...registry import register
class SpecHostField(SpecHost):
def _set_spec_id(self, cls, name):
spec_id = getattr(self, 'spec_id', None)
# Generate a spec_id to register the spec with. The default spec id is
# "<app>:<model>_<field>"
if not spec_id:
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.
super(SpecHostField, self).set_spec_id(spec_id)
class ImageSpecField(SpecHostField):
"""
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,
source=None, cachefile_storage=None, autoconvert=None,
cachefile_backend=None, cachefile_strategy=None, spec=None,
id=None):
SpecHost.__init__(self, processors=processors, format=format,
options=options, cachefile_storage=cachefile_storage,
autoconvert=autoconvert,
cachefile_backend=cachefile_backend,
cachefile_strategy=cachefile_strategy, spec=spec,
spec_id=id)
# TODO: Allow callable for source. See https://github.com/matthewwithanm/django-imagekit/issues/158#issuecomment-10921664
self.source = source
def contribute_to_class(self, cls, name):
# If the source field name isn't defined, figure it out.
source = self.source
if not source:
image_fields = [f.attname for f in cls._meta.fields if
isinstance(f, models.ImageField)]
if len(image_fields) == 0:
raise Exception(
'%s does not define any ImageFields, so your %s'
' ImageSpecField has no image to act on.' %
(cls.__name__, name))
elif len(image_fields) > 1:
raise Exception(
'%s defines multiple ImageFields, but you have not'
' specified a source for your %s ImageSpecField.' %
(cls.__name__, name))
source = image_fields[0]
setattr(cls, name, ImageSpecFileDescriptor(self, name, source))
self._set_spec_id(cls, name)
# Add the model and field as a source for this spec id
register.source_group(self.spec_id, ImageFieldSourceGroup(cls, source))
class ProcessedImageField(models.ImageField, SpecHostField):
"""
ProcessedImageField is an ImageField that runs processors on the uploaded
image *before* saving it to storage. This is in contrast to specs, which
maintain the original. Useful for coercing fileformats or keeping images
within a reasonable size.
"""
attr_class = ProcessedImageFieldFile
def __init__(self, processors=None, format=None, options=None,
verbose_name=None, name=None, width_field=None, height_field=None,
autoconvert=True, spec=None, spec_id=None, **kwargs):
"""
The ProcessedImageField constructor accepts all of the arguments that
the :class:`django.db.models.ImageField` constructor accepts, as well
as the ``processors``, ``format``, and ``options`` arguments of
:class:`imagekit.models.ImageSpecField`.
"""
SpecHost.__init__(self, processors=processors, format=format,
options=options, autoconvert=autoconvert, spec=spec,
spec_id=spec_id)
models.ImageField.__init__(self, verbose_name, name, width_field,
height_field, **kwargs)
def contribute_to_class(self, cls, name):
self._set_spec_id(cls, name)
return super(ProcessedImageField, self).contribute_to_class(cls, name)
try:
from south.modelsinspector import add_introspection_rules
except ImportError:
pass
else:
add_introspection_rules([], [r'^imagekit\.models\.fields\.ProcessedImageField$'])