2012-02-14 16:34:51 +00:00
import os
2008-12-28 21:48:21 +00:00
from django . db import models
2012-10-13 02:36:13 +00:00
from . files import ProcessedImageFieldFile
2012-10-10 04:18:54 +00:00
from . utils import ImageSpecFileDescriptor
2012-10-13 02:36:13 +00:00
from . . . import specs
2012-04-20 01:18:42 +00:00
from . . . utils import suggest_extension
2012-10-13 02:36:13 +00:00
from . . . specs import SpecHost
2012-10-10 04:18:54 +00:00
from . . . specs . sources import ImageFieldSpecSource
2012-02-02 04:26:39 +00:00
2012-10-05 02:56:26 +00:00
class ImageSpecField ( SpecHost ) :
2011-10-31 14:12:03 +00:00
"""
2012-02-11 18:06:48 +00:00
The heart and soul of the ImageKit library , ImageSpecField allows you to add
2011-09-26 00:38:43 +00:00
variants of uploaded images to your models .
2009-12-19 16:01:54 +00:00
2009-03-03 16:44:51 +00:00
"""
2012-04-10 01:25:46 +00:00
def __init__ ( self , processors = None , format = None , options = None ,
2012-10-05 02:56:26 +00:00
image_field = None , storage = None , autoconvert = None ,
image_cache_backend = None , image_cache_strategy = None , spec = None ,
id = None ) :
2011-09-21 15:37:29 +00:00
2012-10-05 01:37:20 +00:00
# The spec accepts a callable value for processors, but it
2012-02-12 04:22:06 +00:00
# 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.
2012-10-05 02:56:26 +00:00
p = lambda file : processors ( instance = file . instance ,
file = file ) if callable ( processors ) else processors
SpecHost . __init__ ( self , processors = p , format = format ,
options = options , storage = storage , autoconvert = autoconvert ,
image_cache_backend = image_cache_backend ,
2012-10-05 03:15:16 +00:00
image_cache_strategy = image_cache_strategy , spec = spec ,
spec_id = id )
2012-10-05 01:37:20 +00:00
2011-09-22 04:24:13 +00:00
self . image_field = image_field
2012-10-05 01:37:20 +00:00
@property
def storage ( self ) :
return self . spec . storage
2011-09-21 15:37:29 +00:00
def contribute_to_class ( self , cls , name ) :
2012-02-17 23:39:51 +00:00
setattr ( cls , name , ImageSpecFileDescriptor ( self , name ) )
2011-10-04 02:51:03 +00:00
2012-10-05 02:56:26 +00:00
# Generate a spec_id to register the spec with. The default spec id is
# "<app>:<model>_<field>"
2012-10-05 03:22:25 +00:00
if not getattr ( self , ' spec_id ' , None ) :
2012-10-05 02:56:26 +00:00
self . spec_id = ( u ' %s : %s _ %s ' % ( cls . _meta . app_label ,
cls . _meta . object_name , name ) ) . lower ( )
2012-10-05 03:22:25 +00:00
# Register the spec with the id. This allows specs to be overridden
# later, from outside of the model definition.
self . set_spec_id ( self . spec_id )
2012-10-05 02:56:26 +00:00
2012-10-13 02:36:13 +00:00
# Add the model and field as a source for this spec id
specs . registry . add_source ( ImageFieldSpecSource ( cls , self . image_field ) ,
self . spec_id )
2012-10-10 04:18:54 +00:00
2011-09-21 15:37:29 +00:00
2012-10-05 03:15:16 +00:00
class ProcessedImageField ( models . ImageField , SpecHost ) :
2011-10-31 14:12:03 +00:00
"""
ProcessedImageField is an ImageField that runs processors on the uploaded
2011-09-26 00:38:43 +00:00
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 .
"""
2011-09-22 04:24:13 +00:00
attr_class = ProcessedImageFieldFile
2012-04-10 01:25:46 +00:00
def __init__ ( self , processors = None , format = None , options = None ,
2011-09-22 04:24:13 +00:00
verbose_name = None , name = None , width_field = None , height_field = None ,
2012-10-05 03:15:16 +00:00
autoconvert = True , spec = None , spec_id = None , * * kwargs ) :
2011-09-26 00:38:43 +00:00
"""
The ProcessedImageField constructor accepts all of the arguments that
2011-10-31 14:12:03 +00:00
the : class : ` django . db . models . ImageField ` constructor accepts , as well
2011-11-16 15:00:35 +00:00
as the ` ` processors ` ` , ` ` format ` ` , and ` ` options ` ` arguments of
2012-04-21 01:43:59 +00:00
: class : ` imagekit . models . ImageSpecField ` .
2011-09-26 00:38:43 +00:00
"""
2012-10-05 03:15:16 +00:00
SpecHost . __init__ ( self , processors = processors , format = format ,
options = options , autoconvert = autoconvert , spec = spec ,
spec_id = spec_id )
2011-09-22 04:24:13 +00:00
models . ImageField . __init__ ( self , verbose_name , name , width_field ,
height_field , * * kwargs )
def get_filename ( self , filename ) :
2012-02-12 04:27:25 +00:00
filename = os . path . normpath ( self . storage . get_valid_name (
os . path . basename ( filename ) ) )
2011-09-22 04:24:13 +00:00
name , ext = os . path . splitext ( filename )
2012-10-05 01:37:20 +00:00
ext = suggest_extension ( filename , self . spec . format )
2012-02-16 13:47:22 +00:00
return u ' %s %s ' % ( name , ext )
2011-10-24 21:58:38 +00:00
try :
from south . modelsinspector import add_introspection_rules
except ImportError :
pass
else :
2012-02-12 19:53:49 +00:00
add_introspection_rules ( [ ] , [ r ' ^imagekit \ .models \ .fields \ .ProcessedImageField$ ' ] )