Usage¶
Models¶
Here is an example model that will create transformed images on save:
from django.db import models
import simpleimages.transforms
import simpleimages.trackers
class YourModel(models.Model):
image = models.ImageField(
upload_to='images/'
)
thumbnail_image = models.ImageField(
blank=True,
null=True,
editable=False,
upload_to='transformed_images/thumbnails/'
)
large_image = models.ImageField(
blank=True,
null=True,
editable=False,
upload_to='transformed_images/large/'
)
transformed_fields = {
'image': {
'thumbnail_image': simpleimages.transforms.Scale(width=10),
'large_image': simpleimages.transforms.Scale(width=200),
}
}
simpleimages.tracking.track_model(YourModel)
track_model()
is called with the model you want to
track. When that model is saved,
perform_transformation()
uses the transformed_fields
attribute of the model to determine a mapping of source to destination
and transform functions.
See transforms
for all the provided transformations.
Dimension Caching¶
I would recommend using
height_field
and
width_field
to save the image
dimensions. Otherwise (at least with
storages.backends.s3boto.S3BotoStorage
), the file will have
to be retrieved once to get url
and another time to get the dimensions:
import os
from django.db import models
import simpleimages.transforms
import simpleimages.trackers
def image_path_function(subfolder, instance, filename):
return os.path.join(
instance.content_name,
'photos',
subfolder,
filename
)
def original_image_path_function(instance, filename):
return image_path_function('original', instance, filename)
def thumbnail_image_path_function(instance, filename):
return image_path_function('thumbnail', instance, filename)
def large_image_path_function(instance, filename):
return image_path_function('large', instance, filename)
class Photo(models.Model):
image = models.ImageField(
upload_to=original_image_path_function,
max_length=1000,
)
thumbnail_image = models.ImageField(
blank=True,
null=True,
editable=False,
upload_to=thumbnail_image_path_function,
height_field='thumbnail_image_height',
width_field='thumbnail_image_width',
max_length=1000
)
large_image = models.ImageField(
blank=True,
null=True,
editable=False,
upload_to=large_image_path_function,
height_field='large_image_height',
width_field='large_image_width',
max_length=1000
)
# cached dimension fields
thumbnail_image_height = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
thumbnail_image_width = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
large_image_height = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
large_image_width = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
transformed_fields = {
'image': {
'thumbnail_image': simpleimages.transforms.Scale(height=600),
'large_image': simpleimages.transforms.Scale(height=800),
}
}
simpleimages.trackers.track_model(Photo)
Performing Transforms Asynchronously¶
By default all transformations are performed when the model is saved.
If you want to instead perform the transformations asynchronously,
for the obvious performance reasons, you by setting
SIMPLEIMAGES_TRANSFORM_CALLER
. Set this to the dotted
path to any function that will take the transform function as its
first argument and the arguments to call it with as subsequent
arguments and keyword arguments. This format was based around
django-rq. To perform all transforms through django-rq set
SIMPLEIMAGES_TRANSFORM_CALLER='django_rq.enqueue'
.
There is also built in support for celery, just set
SIMPLEIMAGES_TRANSFORM_CALLER='simpleimages.callers.celery'
Then you have to account for the fact that sometimes the transformed images won’t be available in time to render them on the page. If you want to fall back to the source image, if the transformed image isn’t rendered yet, use something like this:
import os
from django.db import models
import simpleimages.transforms
import simpleimages.trackers
def image_path_function(subfolder):
return lambda instance, filename: os.path.join(
instance.content_name,
'photos',
subfolder,
filename
)
def original_image_path_function(instance, filename):
image_path_function('original')(instance, filename)
def thumbnail_image_path_function(instance, filename):
image_path_function('thumbnail')(instance, filename)
def large_image_path_function(instance, filename):
image_path_function('large')(instance, filename)
class Photo(models.Model):
image = models.ImageField(
upload_to=original_image_path_function,
max_length=1000,
)
thumbnail_image = models.ImageField(
blank=True,
null=True,
editable=False,
upload_to=thumbnail_image_path_function,
height_field='thumbnail_image_height',
width_field='thumbnail_image_width',
max_length=1000
)
large_image = models.ImageField(
blank=True,
null=True,
editable=False,
upload_to=large_image_path_function,
height_field='large_image_height',
width_field='large_image_width',
max_length=1000
)
# cached dimension fields
thumbnail_image_height = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
thumbnail_image_width = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
large_image_height = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
large_image_width = models.PositiveIntegerField(
null=True,
blank=True,
editable=False,
)
@property
def safe_thumbnail_image(self):
return self.thumbnail_image or self.image
@property
def safe_large_image(self):
return self.large_image or self.image
transformed_fields = {
'image': {
'thumbnail_image': simpleimages.transforms.Scale(height=600),
'large_image': simpleimages.transforms.Scale(height=800),
}
}
simpleimages.trackers.track_model(Photo)
Then access the transformed images with instance.safe_thumbnail_image
instead.
Management Command¶
Since the images are only transformed on the save of the model, if you
change the transform function, the instances will not be updated until
you resave them. If you want to retransform all the images in a model or
app use management.commands.retransform