mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-05-17 09:11:05 +00:00
Doc fixes
This commit is contained in:
parent
0ea497261b
commit
1f86e33d64
10 changed files with 314 additions and 410 deletions
4
AUTHORS
4
AUTHORS
|
|
@ -4,7 +4,7 @@ The field-based API and other post-1.0 stuff was written by the bright people at
|
||||||
HZDG_.
|
HZDG_.
|
||||||
|
|
||||||
Maintainers
|
Maintainers
|
||||||
~~~~~~~~~~~
|
-----------
|
||||||
|
|
||||||
* `Bryan Veloso`_
|
* `Bryan Veloso`_
|
||||||
* `Matthew Tretter`_
|
* `Matthew Tretter`_
|
||||||
|
|
@ -12,7 +12,7 @@ Maintainers
|
||||||
* `Greg Newman`_
|
* `Greg Newman`_
|
||||||
|
|
||||||
Contributors
|
Contributors
|
||||||
~~~~~~~~~~~~
|
------------
|
||||||
|
|
||||||
* `Josh Ourisman`_
|
* `Josh Ourisman`_
|
||||||
* `Jonathan Slenders`_
|
* `Jonathan Slenders`_
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class:
|
||||||
This is pretty similar to our previous example. We don't need to specify a
|
This is pretty similar to our previous example. We don't need to specify a
|
||||||
"source" any more since we're not processing another image field, but we do need
|
"source" any more since we're not processing another image field, but we do need
|
||||||
to pass an "upload_to" argument. This behaves exactly as it does for Django
|
to pass an "upload_to" argument. This behaves exactly as it does for Django
|
||||||
``ImageField``s.
|
ImageFields.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
@ -393,7 +393,7 @@ AdminThumbnail can even use a custom template. For more information, see
|
||||||
|
|
||||||
|
|
||||||
Community
|
Community
|
||||||
---------
|
=========
|
||||||
|
|
||||||
Please use `the GitHub issue tracker <https://github.com/jdriscoll/django-imagekit/issues>`_
|
Please use `the GitHub issue tracker <https://github.com/jdriscoll/django-imagekit/issues>`_
|
||||||
to report bugs with django-imagekit. `A mailing list <https://groups.google.com/forum/#!forum/django-imagekit>`_
|
to report bugs with django-imagekit. `A mailing list <https://groups.google.com/forum/#!forum/django-imagekit>`_
|
||||||
|
|
@ -402,7 +402,7 @@ also exists to discuss the project and ask questions, as well as the official
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
------------
|
============
|
||||||
|
|
||||||
We love contributions! And you don't have to be an expert with the library—or
|
We love contributions! And you don't have to be an expert with the library—or
|
||||||
even Django—to contribute either: ImageKit's processors are standalone classes
|
even Django—to contribute either: ImageKit's processors are standalone classes
|
||||||
|
|
|
||||||
284
docs/advanced_usage.rst
Normal file
284
docs/advanced_usage.rst
Normal file
|
|
@ -0,0 +1,284 @@
|
||||||
|
Advanced Usage
|
||||||
|
**************
|
||||||
|
|
||||||
|
|
||||||
|
Models
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
The ``ImageSpecField`` Shorthand Syntax
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
If you've read the README, you already know what an ``ImageSpecField`` is and
|
||||||
|
the basics of defining one:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from imagekit.models import ImageSpecField
|
||||||
|
from imagekit.processors import ResizeToFill
|
||||||
|
|
||||||
|
class Profile(models.Model):
|
||||||
|
avatar = models.ImageField(upload_to='avatars')
|
||||||
|
avatar_thumbnail = ImageSpecField(source='avatar',
|
||||||
|
processors=[ResizeToFill(100, 50)],
|
||||||
|
format='JPEG',
|
||||||
|
options={'quality': 60})
|
||||||
|
|
||||||
|
This will create an ``avatar_thumbnail`` field which is a resized version of the
|
||||||
|
image stored in the ``avatar`` image field. But this is actually just shorthand
|
||||||
|
for creating an ``ImageSpec``, registering it, and associating it with an
|
||||||
|
``ImageSpecField``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from imagekit import ImageSpec, register
|
||||||
|
from imagekit.models import ImageSpecField
|
||||||
|
from imagekit.processors import ResizeToFill
|
||||||
|
|
||||||
|
class AvatarThumbnail(ImageSpec):
|
||||||
|
processors = [ResizeToFill(100, 50)]
|
||||||
|
format = 'JPEG'
|
||||||
|
options = {'quality': 60}
|
||||||
|
|
||||||
|
register.generator('myapp:profile:avatar_thumbnail', AvatarThumbnail)
|
||||||
|
|
||||||
|
class Profile(models.Model):
|
||||||
|
avatar = models.ImageField(upload_to='avatars')
|
||||||
|
avatar_thumbnail = ImageSpecField(source='avatar',
|
||||||
|
spec_id='myapp:profile:avatar_thumbnail')
|
||||||
|
|
||||||
|
Obviously, the shorthand version is a lot, well…shorter. So why would you ever
|
||||||
|
want to go through the trouble of using the long form? The answer is that the
|
||||||
|
long form—creating an image spec class and registering it—gives you a lot more
|
||||||
|
power over the generated image.
|
||||||
|
|
||||||
|
|
||||||
|
.. _dynamic-specs:
|
||||||
|
|
||||||
|
Specs That Change
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
As you'll remember from the README, an image spec is just a type of image
|
||||||
|
generator that generates a new image from a source image. How does the image
|
||||||
|
spec get access to the source image? Simple! It's passed to the constructor as
|
||||||
|
a keyword argument and stored as an attribute of the spec. Normally, we don't
|
||||||
|
have to concern ourselves with this; the ``ImageSpec`` knows what to do with the
|
||||||
|
source image and we're happy to let it do its thing. However, having access to
|
||||||
|
the source image in our spec class can be very useful…
|
||||||
|
|
||||||
|
Often, when using an ``ImageSpecField``, you may want the spec to vary based on
|
||||||
|
properties of a model. (For example, you might want to store image dimensions on
|
||||||
|
the model and then use them to generate your thumbnail.) Now that we know how to
|
||||||
|
access the source image from our spec, it's a simple matter to extract its model
|
||||||
|
and use it to create our processors list. In fact, ImageKit includes a utility
|
||||||
|
for getting this information.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:emphasize-lines: 11-14
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from imagekit import ImageSpec, register
|
||||||
|
from imagekit.models import ImageSpecField
|
||||||
|
from imagekit.processors import ResizeToFill
|
||||||
|
from imagekit.utils import get_field_info
|
||||||
|
|
||||||
|
class AvatarThumbnail(ImageSpec):
|
||||||
|
format = 'JPEG'
|
||||||
|
options = {'quality': 60}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def processors(self):
|
||||||
|
model, field_name = get_field_info(self.source)
|
||||||
|
return [ResizeToFill(model.thumbnail_width, thumbnail.avatar_height)]
|
||||||
|
|
||||||
|
register.generator('myapp:profile:avatar_thumbnail', AvatarThumbnail)
|
||||||
|
|
||||||
|
class Profile(models.Model):
|
||||||
|
avatar = models.ImageField(upload_to='avatars')
|
||||||
|
avatar_thumbnail = ImageSpecField(source='avatar',
|
||||||
|
spec_id='myapp:profile:avatar_thumbnail')
|
||||||
|
thumbnail_width = models.PositiveIntegerField()
|
||||||
|
thumbnail_height = models.PositiveIntegerField()
|
||||||
|
|
||||||
|
Now each avatar thumbnail will be resized according to the dimensions stored on
|
||||||
|
the model!
|
||||||
|
|
||||||
|
Of course, processors aren't the only thing that can vary based on the model of
|
||||||
|
the source image; spec behavior can change in any way you want.
|
||||||
|
|
||||||
|
|
||||||
|
Optimizing
|
||||||
|
==========
|
||||||
|
|
||||||
|
Unlike Django's ImageFields, ImageKit's ImageSpecFields and template tags don't
|
||||||
|
persist any data in the database. Therefore, in order to know whether an image
|
||||||
|
file needs to be generated, ImageKit needs to check if the file already exists
|
||||||
|
(using the appropriate file storage object`__). The object responsible for
|
||||||
|
performing these checks is called a *cache file backend*.
|
||||||
|
|
||||||
|
|
||||||
|
Cache!
|
||||||
|
------
|
||||||
|
|
||||||
|
By default, ImageKit checks for the existence of a cache file every time you
|
||||||
|
attempt to use the file and, if it doesn't exist, creates it synchronously. This
|
||||||
|
is a very safe behavior because it ensures that your ImageKit-generated images
|
||||||
|
are always available. However, that's a lot of checking with storage and those
|
||||||
|
kinds of operations can be slow—especially if you're using a remote storage—so
|
||||||
|
you'll want to try to avoid them as much as possible.
|
||||||
|
|
||||||
|
Luckily, the default cache file backend makes use of Django's caching
|
||||||
|
abilities to mitigate the number of checks it actually has to do; it will use
|
||||||
|
the cache specified by the ``IMAGEKIT_CACHE_BACKEND`` to save the state of the
|
||||||
|
generated file. If your Django project is running in debug mode
|
||||||
|
(``settings.DEBUG`` is true), this will be a dummy cache by default. Otherwise,
|
||||||
|
it will use your project's default cache.
|
||||||
|
|
||||||
|
In normal operation, your cache files will never be deleted; once they're
|
||||||
|
created, they'll stay created. So the simplest optimization you can make is to
|
||||||
|
set your ``IMAGEKIT_CACHE_BACKEND`` to a cache with a very long, or infinite,
|
||||||
|
timeout.
|
||||||
|
|
||||||
|
|
||||||
|
Even More Advanced
|
||||||
|
------------------
|
||||||
|
|
||||||
|
For many applications—particularly those using local storage for generated image
|
||||||
|
files—a cache with a long timeout is all the optimization you'll need. However,
|
||||||
|
there may be times when that simply doesn't cut it. In these cases, you'll want
|
||||||
|
to change when the generation is actually done.
|
||||||
|
|
||||||
|
The objects responsible for specifying when cache files are created are
|
||||||
|
called *cache file strategies*. The default strategy can be set using the
|
||||||
|
``IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY`` setting, and its default value is
|
||||||
|
`'imagekit.cachefiles.strategies.JustInTime'`. As we've already seen above,
|
||||||
|
the "just in time" strategy determines whether a file needs to be generated each
|
||||||
|
time it's accessed and, if it does, generates it synchronously (that is, as part
|
||||||
|
of the request-response cycle).
|
||||||
|
|
||||||
|
Another strategy is to simply assume the file exists. This requires the fewest
|
||||||
|
number of checks (zero!), so we don't have to worry about expensive IO. The
|
||||||
|
strategy that takes this approach is
|
||||||
|
``imagekit.cachefiles.strategies.Optimistic``. In order to use this
|
||||||
|
strategy, either set the ``IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY`` setting or,
|
||||||
|
to use it on a per-generator basis, set the ``cachefile_strategy`` attribute
|
||||||
|
of your spec or generator. Avoiding checking for file existence can be a real
|
||||||
|
boon to performance, but it also means that ImageKit has no way to know when a
|
||||||
|
file needs to be generated—well, at least not all the time.
|
||||||
|
|
||||||
|
With image specs, we can know at least some of the times that a new file needs
|
||||||
|
to be generated: whenever the source image is created or changed. For this
|
||||||
|
reason, the optimistic strategy defines callbacks for these events. Every
|
||||||
|
source registered with ImageKit will automatically cause its specs' files to be
|
||||||
|
generated when it is created or changed.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In order to understand source registration, read :ref:`source-groups`
|
||||||
|
|
||||||
|
If you have specs that :ref:`change based on attributes of the source
|
||||||
|
<dynamic-specs>`, that's not going to cut it, though; the file will also need to
|
||||||
|
be generated when those attributes change. Likewise, image generators that don't
|
||||||
|
have sources (i.e. generators that aren't specs) won't cause files to be
|
||||||
|
generated automatically when using the optimistic strategy. (ImageKit can't know
|
||||||
|
when those need to be generated, if not on access.) In both cases, you'll have
|
||||||
|
to trigger the file generation yourself—either by generating the file in code
|
||||||
|
when necessary, or by periodically running the ``generateimages`` management
|
||||||
|
command. Luckily, ImageKit makes this pretty easy:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from imagekit.cachefiles import LazyGeneratedImageFile
|
||||||
|
|
||||||
|
file = LazyGeneratedImageFile('myapp:profile:avatar_thumbnail', source=source_file)
|
||||||
|
file.generate()
|
||||||
|
|
||||||
|
One final situation in which images won't be generated automatically when using
|
||||||
|
the optimistic strategy is when you use a spec with a source that hasn't been
|
||||||
|
registered with it. Unlike the previous two examples, this situation cannot be
|
||||||
|
rectified by running the ``generateimages`` management command, for the simple
|
||||||
|
reason that the command has no way of knowing it needs to generate a file for
|
||||||
|
that spec from that source. Typically, this situation would arise when using the
|
||||||
|
template tags. Unlike ImageSpecFields, which automatically register all the
|
||||||
|
possible source images with the spec you define, the template tags
|
||||||
|
("generateimage" and "thumbnail") let you use any spec with any source.
|
||||||
|
Therefore, in order to generate the appropriate files using the
|
||||||
|
``generateimages`` management command, you'll need to first register a source
|
||||||
|
group that represents all of the sources you wish to use with the corresponding
|
||||||
|
specs. See :ref:`source-groups` for more information.
|
||||||
|
|
||||||
|
|
||||||
|
.. _source-groups:
|
||||||
|
|
||||||
|
Source Groups
|
||||||
|
=============
|
||||||
|
|
||||||
|
When you run the ``generateimages`` management command, how does ImageKit know
|
||||||
|
which source images to use with which specs? Obviously, when you define an
|
||||||
|
ImageSpecField, the source image is being connected to a spec, but what's going
|
||||||
|
on underneath the hood?
|
||||||
|
|
||||||
|
The answer is that, when you define an ImageSpecField, ImageKit automatically
|
||||||
|
creates and registers an object called a *source group*. Source groups are
|
||||||
|
responsible for two things:
|
||||||
|
|
||||||
|
1. They dispatch signals when a source is created, changed, or deleted, and
|
||||||
|
2. They expose a generator method that enumerates source files.
|
||||||
|
|
||||||
|
When these objects are registered (using ``imagekit.register.source_group()``),
|
||||||
|
their signals will trigger callbacks on the cache file strategies associated
|
||||||
|
with image specs that use the source. (So, for example, you can chose to
|
||||||
|
generate a file every time the source image changes.) In addition, the generator
|
||||||
|
method is used (indirectly) to create the list of files to generate with the
|
||||||
|
``generateimages`` management command.
|
||||||
|
|
||||||
|
Currently, there is only one source group class bundled with ImageKit—the one
|
||||||
|
used by ImageSpecFields. This source group
|
||||||
|
(``imagekit.specs.sourcegroups.ImageFieldSourceGroup``) represents an ImageField
|
||||||
|
on every instance of a particular model. In terms of the above description, the
|
||||||
|
instance ``ImageFieldSourceGroup(Profile, 'avatar')`` 1) dispatches a signal
|
||||||
|
every time the image in Profile's avatar ImageField changes, and 2) exposes a
|
||||||
|
generator method that iterates over every Profile's "avatar" image.
|
||||||
|
|
||||||
|
Chances are, this is the only source group you will ever need to use, however,
|
||||||
|
ImageKit lets you define and register custom source groups easily. This may be
|
||||||
|
useful, for example, if you're using the template tags "generateimage" and
|
||||||
|
"thumbnail" and the optimistic cache file strategy. Again, the purpose is
|
||||||
|
to tell ImageKit which specs are used with which sources (so the
|
||||||
|
"generateimages" management command can generate those files) and when the
|
||||||
|
source image has been created or changed (so that the strategy has the
|
||||||
|
opportunity to act on it).
|
||||||
|
|
||||||
|
A simple example of a custom source group class is as follows:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
|
||||||
|
class JpegsInADirectory(object):
|
||||||
|
def __init__(self, dir):
|
||||||
|
self.dir = dir
|
||||||
|
|
||||||
|
def files(self):
|
||||||
|
os.chdir(self.dir)
|
||||||
|
for name in glob.glob('*.jpg'):
|
||||||
|
yield open(name)
|
||||||
|
|
||||||
|
Instances of this class could then be registered with one or more spec id:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from imagekit import register
|
||||||
|
|
||||||
|
register.source_group('myapp:profile:avatar_thumbnail', JpegsInADirectory('/path/to/some/pics'))
|
||||||
|
|
||||||
|
Running the "generateimages" management command would now cause thumbnails to be
|
||||||
|
generated (using the "myapp:profile:avatar_thumbnail" spec) for each of the
|
||||||
|
JPEGs in `/path/to/some/pics`.
|
||||||
|
|
||||||
|
Note that, since this source group doesnt send the `source_created` or
|
||||||
|
`source_changed` signals, the corresponding cache file strategy callbacks
|
||||||
|
would not be called for them.
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
The ``ImageSpecField`` Shorthand Syntax
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
If you've read the README, you already know what an ``ImageSpecField`` is and
|
|
||||||
the basics of defining one:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from imagekit.models import ImageSpecField
|
|
||||||
from imagekit.processors import ResizeToFill
|
|
||||||
|
|
||||||
class Profile(models.Model):
|
|
||||||
avatar = models.ImageField(upload_to='avatars')
|
|
||||||
avatar_thumbnail = ImageSpecField(source='avatar',
|
|
||||||
processors=[ResizeToFill(100, 50)],
|
|
||||||
format='JPEG',
|
|
||||||
options={'quality': 60})
|
|
||||||
|
|
||||||
This will create an ``avatar_thumbnail`` field which is a resized version of the
|
|
||||||
image stored in the ``avatar`` image field. But this is actually just shorthand
|
|
||||||
for creating an ``ImageSpec``, registering it, and associating it with an
|
|
||||||
``ImageSpecField``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from imagekit import ImageSpec, register
|
|
||||||
from imagekit.models import ImageSpecField
|
|
||||||
from imagekit.processors import ResizeToFill
|
|
||||||
|
|
||||||
class AvatarThumbnail(ImageSpec):
|
|
||||||
processors = [ResizeToFill(100, 50)]
|
|
||||||
format = 'JPEG'
|
|
||||||
options = {'quality': 60}
|
|
||||||
|
|
||||||
register.generator('myapp:profile:avatar_thumbnail', AvatarThumbnail)
|
|
||||||
|
|
||||||
class Profile(models.Model):
|
|
||||||
avatar = models.ImageField(upload_to='avatars')
|
|
||||||
avatar_thumbnail = ImageSpecField(source='avatar',
|
|
||||||
spec_id='myapp:profile:avatar_thumbnail')
|
|
||||||
|
|
||||||
Obviously, the shorthand version is a lot, well…shorter. So why would you ever
|
|
||||||
want to go through the trouble of using the long form? The answer is that the
|
|
||||||
long form—creating an image spec class and registering it—gives you a lot more
|
|
||||||
power over the generated image.
|
|
||||||
|
|
||||||
|
|
||||||
Specs That Change
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
As you'll remember from the README, an image spec is just a type of image
|
|
||||||
generator that generates a new image from a source image. How does the image
|
|
||||||
spec get access to the source image? Simple! It's passed to the constructor as
|
|
||||||
a keyword argument and stored as an attribute of the spec. Normally, we don't
|
|
||||||
have to concern ourselves with this; the ``ImageSpec`` knows what to do with the
|
|
||||||
source image and we're happy to let it do its thing. However, having access to
|
|
||||||
the source image in our spec class can be very useful…
|
|
||||||
|
|
||||||
Often, when using an ``ImageSpecField``, you may want the spec to vary based on
|
|
||||||
properties of a model. (For example, you might want to store image dimensions on
|
|
||||||
the model and then use them to generate your thumbnail.) Now that we know how to
|
|
||||||
access the source image from our spec, it's a simple matter to extract its model
|
|
||||||
and use it to create our processors list. In fact, ImageKit includes a utility
|
|
||||||
for getting this information.
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
:emphasize-lines: 11-14
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from imagekit import ImageSpec, register
|
|
||||||
from imagekit.models import ImageSpecField
|
|
||||||
from imagekit.processors import ResizeToFill
|
|
||||||
from imagekit.utils import get_field_info
|
|
||||||
|
|
||||||
class AvatarThumbnail(ImageSpec):
|
|
||||||
format = 'JPEG'
|
|
||||||
options = {'quality': 60}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def processors(self):
|
|
||||||
model, field_name = get_field_info(self.source)
|
|
||||||
return [ResizeToFill(model.thumbnail_width, thumbnail.avatar_height)]
|
|
||||||
|
|
||||||
register.generator('myapp:profile:avatar_thumbnail', AvatarThumbnail)
|
|
||||||
|
|
||||||
class Profile(models.Model):
|
|
||||||
avatar = models.ImageField(upload_to='avatars')
|
|
||||||
avatar_thumbnail = ImageSpecField(source='avatar',
|
|
||||||
spec_id='myapp:profile:avatar_thumbnail')
|
|
||||||
thumbnail_width = models.PositiveIntegerField()
|
|
||||||
thumbnail_height = models.PositiveIntegerField()
|
|
||||||
|
|
||||||
Now each avatar thumbnail will be resized according to the dimensions stored on
|
|
||||||
the model!
|
|
||||||
|
|
||||||
Of course, processors aren't the only thing that can vary based on the model of
|
|
||||||
the source image; spec behavior can change in any way you want.
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
Unlike Django's ImageFields, ImageKit's ImageSpecFields and template tags don't
|
|
||||||
persist any data in the database. Therefore, in order to know whether an image
|
|
||||||
file needs to be generated, ImageKit needs to check if the file already exists
|
|
||||||
(using the appropriate file storage object`__). The object responsible for
|
|
||||||
performing these checks is called a *cache file backend*.
|
|
||||||
|
|
||||||
|
|
||||||
Cache!
|
|
||||||
------
|
|
||||||
|
|
||||||
By default, ImageKit checks for the existence of a cache file every time you
|
|
||||||
attempt to use the file and, if it doesn't exist, creates it synchronously. This
|
|
||||||
is a very safe behavior because it ensures that your ImageKit-generated images
|
|
||||||
are always available. However, that's a lot of checking with storage and those
|
|
||||||
kinds of operations can be slow—especially if you're using a remote storage—so
|
|
||||||
you'll want to try to avoid them as much as possible.
|
|
||||||
|
|
||||||
Luckily, the default cache file backend makes use of Django's caching
|
|
||||||
abilities to mitigate the number of checks it actually has to do; it will use
|
|
||||||
the cache specified by the ``IMAGEKIT_CACHE_BACKEND`` to save the state of the
|
|
||||||
generated file. If your Django project is running in debug mode
|
|
||||||
(``settings.DEBUG`` is true), this will be a dummy cache by default. Otherwise,
|
|
||||||
it will use your project's default cache.
|
|
||||||
|
|
||||||
In normal operation, your cache files will never be deleted; once they're
|
|
||||||
created, they'll stay created. So the simplest optimization you can make is to
|
|
||||||
set your ``IMAGEKIT_CACHE_BACKEND`` to a cache with a very long, or infinite,
|
|
||||||
timeout.
|
|
||||||
|
|
||||||
|
|
||||||
Even More Advanced
|
|
||||||
------------------
|
|
||||||
|
|
||||||
For many applications—particularly those using local storage for generated image
|
|
||||||
files—a cache with a long timeout is all the optimization you'll need. However,
|
|
||||||
there may be times when that simply doesn't cut it. In these cases, you'll want
|
|
||||||
to change when the generation is actually done.
|
|
||||||
|
|
||||||
The objects responsible for specifying when cache files are created are
|
|
||||||
called *cache file strategies*. The default strategy can be set using the
|
|
||||||
``IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY`` setting, and its default value is
|
|
||||||
`'imagekit.cachefiles.strategies.JustInTime'`. As we've already seen above,
|
|
||||||
the "just in time" strategy determines whether a file needs to be generated each
|
|
||||||
time it's accessed and, if it does, generates it synchronously (that is, as part
|
|
||||||
of the request-response cycle).
|
|
||||||
|
|
||||||
Another strategy is to simply assume the file exists. This requires the fewest
|
|
||||||
number of checks (zero!), so we don't have to worry about expensive IO. The
|
|
||||||
strategy that takes this approach is
|
|
||||||
``imagekit.cachefiles.strategies.Optimistic``. In order to use this
|
|
||||||
strategy, either set the ``IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY`` setting or,
|
|
||||||
to use it on a per-generator basis, set the ``cachefile_strategy`` attribute
|
|
||||||
of your spec or generator. Avoiding checking for file existence can be a real
|
|
||||||
boon to performance, but it also means that ImageKit has no way to know when a
|
|
||||||
file needs to be generated—well, at least not all the time.
|
|
||||||
|
|
||||||
With image specs, we can know at least some of the times that a new file needs
|
|
||||||
to be generated: whenever the source image is created or changed. For this
|
|
||||||
reason, the optimistic strategy defines callbacks for these events. Every
|
|
||||||
`source registered with ImageKit`__ will automatically cause its specs' files to
|
|
||||||
be generated when it is created or changed.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
In order to understand source registration, read :ref:`source-groups`
|
|
||||||
|
|
||||||
If you have specs that `change based on attributes of the source`__, that's not
|
|
||||||
going to cut it, though; the file will also need to be generated when those
|
|
||||||
attributes change. Likewise, image generators that don't have sources (i.e.
|
|
||||||
generators that aren't specs) won't cause files to be generated automatically
|
|
||||||
when using the optimistic strategy. (ImageKit can't know when those need to be
|
|
||||||
generated, if not on access.) In both cases, you'll have to trigger the file
|
|
||||||
generation yourself—either by generating the file in code when necessary, or by
|
|
||||||
periodically running the ``generateimages`` management command. Luckily,
|
|
||||||
ImageKit makes this pretty easy:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from imagekit.cachefiles import LazyGeneratedImageFile
|
|
||||||
|
|
||||||
file = LazyGeneratedImageFile('myapp:profile:avatar_thumbnail', source=source_file)
|
|
||||||
file.generate()
|
|
||||||
|
|
||||||
One final situation in which images won't be generated automatically when using
|
|
||||||
the optimistic strategy is when you use a spec with a source that hasn't been
|
|
||||||
registered with it. Unlike the previous two examples, this situation cannot be
|
|
||||||
rectified by running the ``generateimages`` management command, for the simple
|
|
||||||
reason that the command has no way of knowing it needs to generate a file for
|
|
||||||
that spec from that source. Typically, this situation would arise when using the
|
|
||||||
template tags. Unlike ImageSpecFields, which automatically register all the
|
|
||||||
possible source images with the spec you define, the template tags
|
|
||||||
("generateimage" and "thumbnail") let you use any spec with any source.
|
|
||||||
Therefore, in order to generate the appropriate files using the
|
|
||||||
``generateimages`` management command, you'll need to first register a source
|
|
||||||
group that represents all of the sources you wish to use with the corresponding
|
|
||||||
specs. See :ref:`source-groups` for more information.
|
|
||||||
|
|
||||||
|
|
||||||
__ https://docs.djangoproject.com/en/dev/ref/files/storage/
|
|
||||||
__
|
|
||||||
__
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
.. _source-groups:
|
|
||||||
|
|
||||||
When you run the ``generateimages`` management command, how does ImageKit know
|
|
||||||
which source images to use with which specs? Obviously, when you define an
|
|
||||||
ImageSpecField, the source image is being connected to a spec, but what's going
|
|
||||||
on underneath the hood?
|
|
||||||
|
|
||||||
The answer is that, when you define an ImageSpecField, ImageKit automatically
|
|
||||||
creates and registers an object called a *source group*. Source groups are
|
|
||||||
responsible for two things:
|
|
||||||
|
|
||||||
1. They dispatch signals when a source is created, changed, or deleted, and
|
|
||||||
2. They expose a generator method that enumerates source files.
|
|
||||||
|
|
||||||
When these objects are registered (using ``imagekit.register.source_group()``),
|
|
||||||
their signals will trigger callbacks on the cache file strategies associated
|
|
||||||
with image specs that use the source. (So, for example, you can chose to
|
|
||||||
generate a file every time the source image changes.) In addition, the generator
|
|
||||||
method is used (indirectly) to create the list of files to generate with the
|
|
||||||
``generateimages`` management command.
|
|
||||||
|
|
||||||
Currently, there is only one source group class bundled with ImageKit—the one
|
|
||||||
used by ImageSpecFields. This source group
|
|
||||||
(``imagekit.specs.sourcegroups.ImageFieldSourceGroup``) represents an ImageField
|
|
||||||
on every instance of a particular model. In terms of the above description, the
|
|
||||||
instance ``ImageFieldSourceGroup(Profile, 'avatar')`` 1) dispatches a signal
|
|
||||||
every time the image in Profile's avatar ImageField changes, and 2) exposes a
|
|
||||||
generator method that iterates over every Profile's "avatar" image.
|
|
||||||
|
|
||||||
Chances are, this is the only source group you will ever need to use, however,
|
|
||||||
ImageKit lets you define and register custom source groups easily. This may be
|
|
||||||
useful, for example, if you're using the template tags "generateimage" and
|
|
||||||
"thumbnail" and the optimistic cache file strategy. Again, the purpose is
|
|
||||||
to tell ImageKit which specs are used with which sources (so the
|
|
||||||
"generateimages" management command can generate those files) and when the
|
|
||||||
source image has been created or changed (so that the strategy has the
|
|
||||||
opportunity to act on it).
|
|
||||||
|
|
||||||
A simple example of a custom source group class is as follows:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
|
|
||||||
class JpegsInADirectory(object):
|
|
||||||
def __init__(self, dir):
|
|
||||||
self.dir = dir
|
|
||||||
|
|
||||||
def files(self):
|
|
||||||
os.chdir(self.dir)
|
|
||||||
for name in glob.glob('*.jpg'):
|
|
||||||
yield open(name)
|
|
||||||
|
|
||||||
Instances of this class could then be registered with one or more spec id:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from imagekit import register
|
|
||||||
|
|
||||||
register.source_group('myapp:profile:avatar_thumbnail', JpegsInADirectory('/path/to/some/pics'))
|
|
||||||
|
|
||||||
Running the "generateimages" management command would now cause thumbnails to be
|
|
||||||
generated (using the "myapp:profile:avatar_thumbnail" spec) for each of the
|
|
||||||
JPEGs in `/path/to/some/pics`.
|
|
||||||
|
|
||||||
Note that, since this source group doesnt send the `source_created` or
|
|
||||||
`source_changed` signals, the corresponding cache file strategy callbacks
|
|
||||||
would not be called for them.
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
API Reference
|
|
||||||
=============
|
|
||||||
|
|
||||||
|
|
||||||
:mod:`models` Module
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. automodule:: imagekit.models.fields
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
:mod:`processors` Module
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
.. automodule:: imagekit.processors
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. automodule:: imagekit.processors.resize
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. automodule:: imagekit.processors.crop
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
:mod:`admin` Module
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. automodule:: imagekit.admin
|
|
||||||
:members:
|
|
||||||
|
|
@ -10,7 +10,7 @@ Settings
|
||||||
.. currentmodule:: django.conf.settings
|
.. currentmodule:: django.conf.settings
|
||||||
|
|
||||||
|
|
||||||
.. attribute:: IMAGEKIT_CACHE_DIR
|
.. attribute:: IMAGEKIT_CACHEFILE_DIR
|
||||||
|
|
||||||
:default: ``'CACHE/images'``
|
:default: ``'CACHE/images'``
|
||||||
|
|
||||||
|
|
@ -27,16 +27,16 @@ Settings
|
||||||
will be used.
|
will be used.
|
||||||
|
|
||||||
|
|
||||||
.. attribute:: IMAGEKIT_DEFAULT_IMAGE_CACHE_BACKEND
|
.. attribute:: IMAGEKIT_DEFAULT_CACHEFILE_BACKEND
|
||||||
|
|
||||||
:default: ``'imagekit.imagecache.backends.Simple'``
|
:default: ``'imagekit.cachefiles.backends.Simple'``
|
||||||
|
|
||||||
Specifies the class that will be used to validate cached image files.
|
Specifies the class that will be used to validate cached image files.
|
||||||
|
|
||||||
|
|
||||||
.. attribute:: IMAGEKIT_DEFAULT_IMAGE_CACHE_STRATEGY
|
.. attribute:: IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY
|
||||||
|
|
||||||
:default: ``'imagekit.imagecache.strategies.JustInTime'``
|
:default: ``'imagekit.cachefiles.strategies.JustInTime'``
|
||||||
|
|
||||||
The class responsible for specifying how and when cache files are
|
The class responsible for specifying how and when cache files are
|
||||||
generated.
|
generated.
|
||||||
|
|
@ -58,80 +58,17 @@ Settings
|
||||||
A cache prefix to be used when values are stored in ``IMAGEKIT_CACHE_BACKEND``
|
A cache prefix to be used when values are stored in ``IMAGEKIT_CACHE_BACKEND``
|
||||||
|
|
||||||
|
|
||||||
Optimization
|
.. attribute:: IMAGEKIT_CACHEFILE_NAMER
|
||||||
------------
|
|
||||||
|
|
||||||
Not surprisingly, the trick to getting the most out of ImageKit is to reduce the
|
:default: ``'imagekit.cachefiles.namers.hash'``
|
||||||
number of I/O operations. This can be especially important if your source files
|
|
||||||
aren't stored on the same server as the application.
|
A function responsible for generating file names for non-spec cache files.
|
||||||
|
|
||||||
|
|
||||||
Image Cache Strategies
|
.. attribute:: IMAGEKIT_SPEC_CACHEFILE_NAMER
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
An important way of reducing the number of I/O operations that ImageKit makes is
|
:default: ``'imagekit.cachefiles.namers.source_name_as_path'``
|
||||||
by controlling when cached images are validated. This is done through "image
|
|
||||||
cache strategies"—objects that associate signals dispatched on the source file
|
|
||||||
with file actions. The default image cache strategy is
|
|
||||||
``'imagekit.imagecache.strategies.JustInTime'``; it looks like this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
A function responsible for generating file names for cache files that
|
||||||
|
correspond to image specs. Since you will likely want to base the name of
|
||||||
class JustInTime(object):
|
your cache files on the name of the source, this extra setting is provided.
|
||||||
def before_access(self, file):
|
|
||||||
validate_now(file)
|
|
||||||
|
|
||||||
When this strategy is used, the cache file is validated only immediately before
|
|
||||||
it's required—for example, when you access its url, path, or contents. This
|
|
||||||
strategy is exceedingly safe: by guaranteeing the presence of the file before
|
|
||||||
accessing it, you run no risk of it not being there. However, this strategy can
|
|
||||||
also be costly: verifying the existence of the cache file every time you access
|
|
||||||
it can be slow—particularly if the file is on another server. For this reason,
|
|
||||||
ImageKit provides another strategy: ``imagekit.imagecache.strategies.Optimistic``.
|
|
||||||
Unlike the just-in-time strategy, it does not validate the cache file when it's
|
|
||||||
accessed, but rather only when the soure file is created or changed. Later, when
|
|
||||||
the cache file is accessed, it is presumed to still be present.
|
|
||||||
|
|
||||||
If neither of these strategies suits your application, you can create your own
|
|
||||||
strategy class. For example, you may wish to validate the file immediately when
|
|
||||||
it's accessed, but schedule validation using Celery when the source file is
|
|
||||||
saved or changed:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from imagekit.imagecache.actions import validate_now, deferred_validate
|
|
||||||
|
|
||||||
class CustomImageCacheStrategy(object):
|
|
||||||
|
|
||||||
def before_access(self, file):
|
|
||||||
validate_now(file)
|
|
||||||
|
|
||||||
def on_source_created(self, file):
|
|
||||||
deferred_validate(file)
|
|
||||||
|
|
||||||
def on_source_changed(self, file):
|
|
||||||
deferred_validate(file)
|
|
||||||
|
|
||||||
To use this cache strategy, you need only set the ``IMAGEKIT_DEFAULT_IMAGE_CACHE_STRATEGY``
|
|
||||||
setting, or set the ``image_cache_strategy`` attribute of your image spec.
|
|
||||||
|
|
||||||
|
|
||||||
Django Cache Backends
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
In the "Image Cache Strategies" section above, we said that the just-in-time
|
|
||||||
strategy verifies the existence of the cache file every time you access
|
|
||||||
it, however, that's not exactly true. Cache files are actually validated using
|
|
||||||
image cache backends, and the default (``imagekit.imagecache.backends.Simple``)
|
|
||||||
memoizes the cache state (valid or invalid) using Django's cache framework. By
|
|
||||||
default, ImageKit will use a dummy cache backend when your project is in debug
|
|
||||||
mode (``DEBUG = True``), and the "default" cache (from your ``CACHES`` setting)
|
|
||||||
when ``DEBUG`` is ``False``. Since other parts of your project may have
|
|
||||||
different cacheing needs, though, ImageKit has an ``IMAGEKIT_CACHE_BACKEND``
|
|
||||||
setting, which allows you to specify a different cache.
|
|
||||||
|
|
||||||
In most cases, you won't be deleting you cached files once they're created, so
|
|
||||||
using a cache with a large timeout is a great way to optimize your site. Using
|
|
||||||
a cache that never expires would essentially negate the cost of the just-in-time
|
|
||||||
strategy, giving you the benefit of generating images on demand without the cost
|
|
||||||
of unnecessary future filesystem checks.
|
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,24 @@
|
||||||
Getting Started
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. include:: ../README.rst
|
.. include:: ../README.rst
|
||||||
|
|
||||||
|
|
||||||
Commands
|
|
||||||
--------
|
|
||||||
|
|
||||||
.. automodule:: imagekit.management.commands.ikcacheinvalidate
|
|
||||||
|
|
||||||
.. automodule:: imagekit.management.commands.ikcachevalidate
|
|
||||||
|
|
||||||
|
|
||||||
Authors
|
Authors
|
||||||
-------
|
=======
|
||||||
|
|
||||||
.. include:: ../AUTHORS
|
.. include:: ../AUTHORS
|
||||||
|
|
||||||
|
|
||||||
Community
|
|
||||||
---------
|
|
||||||
|
|
||||||
The official Freenode channel for ImageKit is `#imagekit <irc://irc.freenode.net/imagekit>`_.
|
|
||||||
You should always find some fine people to answer your questions
|
|
||||||
about ImageKit there.
|
|
||||||
|
|
||||||
|
|
||||||
Digging Deeper
|
|
||||||
--------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
configuration
|
|
||||||
apireference
|
|
||||||
changelog
|
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
* :ref:`search`
|
* :ref:`search`
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
configuration
|
||||||
|
advanced_usage
|
||||||
|
changelog
|
||||||
|
upgrading
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ ImageKit 3.0 introduces new APIs and tools that augment, improve, and in some
|
||||||
cases entirely replace old IK workflows. Below, you'll find some useful guides
|
cases entirely replace old IK workflows. Below, you'll find some useful guides
|
||||||
for migrating your ImageKit 2.0 apps over to the shiny new IK3.
|
for migrating your ImageKit 2.0 apps over to the shiny new IK3.
|
||||||
|
|
||||||
|
|
||||||
Model Specs
|
Model Specs
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue