========
sorl-url
========

Out-of-band processing for sorl-thumbnail thumbnails.

Installation & Setup
====================

Installation
------------

Installation is as easy as ``pip install sorl-url`` though the latest version is always available on `GitHub <https://github.com/bolster/sorl-url/>`_.

Setup
-----

1. Add ``sorl-url`` to your ``settings.INSTALLED_APPS``.
2. Add ``url(r'^thumbnails/', include('sorl_url.urls'))`` to your URL configuration.
3. Configure your defaults (see Usage_ below).

Requirements
============

Base Requirements
-----------------

* sorl-thumbnail 11.12+

sorl-thumbnail
--------------

Mikko Hellsing's excellent `sorl-thumbnail <https://github.com/sorl/sorl-thumbnail>`_ is the only direct requirement for this project.

You can read more about sorl-thumbnail, its `requirements <http://sorl-thumbnail.readthedocs.org/en/latest/requirements.html>`_ and how it is `installed and configured <http://sorl-thumbnail.readthedocs.org/en/latest/installation.html>`_ at `Read the Docs <http://readthedocs.org/projects/sorl-thumbnail/>`_.

.. _usage:

Usage
=====

The core workflow is built around usage through a template tag named ``image_url`` in the ``sorl_url`` template tag library.

``sorl_url`` does not serve images directly. It generates them as sorl-thumbnail would (storing them in a cache via ``settings.THUMBNAIL_STORAGE``) and then redirects to the URL of the generated image.

Template Tags
-------------

The primary invocation of ``sorl_url`` is through the ``image_url`` template tag, which uses the following basic syntax::

    {% image_url SOURCE FIELD_NAME GEOMETRY [key1=VAL1 key2=VAL2...] %}

or::

    {% image_url SOURCE FIELD_NAME GEOMETRY [key1=VAL1 key2=VAL2...] as VAR %}
        The image URL is {{ VAR }}.
    {% empty %}
        This block is optional.
    {% endimage_url}

An example invocation might be::

    <% load image_url %>

    <img src='{% image_url user.get_profile "avatar" "50x50"  %}' alt="{{ user.get_full_name }}" />

Which might render as *(linebreaks added)*::

    <img src='/media/profiles/avatar/username.png?config=eyJnZW9tZXRyeSI6IjUwe
              DUwIiwib3B0aW9ucyI6eyJjcm9wIjoiY2VudGVyIn19:1SiodC:_wL4eWd9crnlF
              X8VJFXgBJdISEQ' alt="Jane Doe" />

For a complete list of available options, please consult the documentation for sorl-thumbnail's `thumbnail template tag <http://sorl-thumbnail.readthedocs.org/en/latest/template.html#thumbnail>`_.

URL Structure
-------------

sorl-url generates URLs of the form: ``/prefix/MODEL_NAME/FIELD_NAME/KEY.ext?config=OPTIONS``

``prefix`` is dictated by the location at which the ``sorl-url`` views are included in the URLConf

``OPTIONS`` is a configuration including the size and other options signed and obfuscated by the ``django.core.signing`` module described in `URL Arguments`_ below.

**Note:** the ``config`` query string argument is mandatory. Failure to provide a ``config`` will result in a 404.


.. _URL arguments:

URL Arguments
~~~~~~~~~~~~~

Image options are passed via the ``config`` query string argument. The values are obfuscated but **not** enscrypted. They are serialized, compressed and signed by ``django.core.signing``.

Default options specified in ``SORL_URL_CONFIG`` and other sorl settings are **not** included in the query string. However, the signature is salted with a variety of attributes, including the underlying filename and a hash of all relevant settings to ensure that as underlying attributes and settings are updated, the URL will change as well. Note that this means that a change to ``SORL_URL_CONFIG``, for example, will result in all URLs being updated. This may or may not result in new images being generated by sorl (depending on what has been changed).

**Debugging**: To easily see what arguments are being passed for rendering, simply set ``settings.THUMBNAIL_DEBUG`` to ``True`` and append ``&echo=True`` to any generated URL to see what options are being passed.

Configuring Settings
--------------------

The available options and defaults are controlled by the ``SORL_URL_CONFIG`` setting.

``SORL_URL_CONFIG`` must be a dictionary-like object with keys corresponding to the ``MODEL_NAME`` URL component and a dictionary-like value representing the *model configuration*.

Additionally ``SORL_URL_PERMANENT_REDIRECT`` (default: ``False``) can be used to control the type of redirect that is used.

Model Configuration
~~~~~~~~~~~~~~~~~~~

Each model configuration offers the following options:

* ``model``: either a model class or the Django-style dotted name (``app_label.ModelName``) **(required)**
* ``fields``: a list of the attributes on model that should be exposed by this configuration; alternatively a 2-tuple of the format ``(attr_name, options)`` where ``options`` is a dictionary containing default to be passed to the sorl backend's ``get_thumbnail`` method **(required)**
* ``backend``: the sorl backend, as a string representing the module path, to be used *(optional; defaults to ``sorl.thumbnail.default.backend``)*
* ``key_field``: the field to be used in object lookups for the key portion of the URL *(optional; defaults to ``id``)*
* ``key_filter``: a transformation function to be applied to the key URL component to ensure it is properly prepared for the ORM *(optional; defaults to ``lambda x: int(x)``)*
* ``options``: a dictionary containing default options to be passed to the sorl backend's ``get_thumbnail`` method. Individual fields may override these options. *(optional; defaults to ``{}``)*

Configuration Examples
~~~~~~~~~~~~~~~~~~~~~~

A minimal configuration might look like::

    SORL_URL_CONFIG = {
        'profiles': {
            'model': 'profiles.Profile',
            'fields': ['avatar'],
        }
    }

The above configuration would mean that the following URL would be valid: ``/prefix/profiles/avatar/1.png?config=CONFIG``

A more advanced configuration might look like::

    SORL_URL_CONFIG = {
        'profiles': {
            'model': 'profiles.Profile',
            'fields': [
                ('avatar', {
                    'format': 'PNG',
                    'crop': 'top',
                    'upscale': True
                }),
                ('background': {
                    'format': 'JPEG',
                    'quality': 90,
                    'colorspace': 'GRAY'
                }
                )
            ],
            'key_field': 'user__username',
            'key_filter': None  # The default is lambda x: int(x),
                                # but None implies a no-op (lambda x: x)
        }
    }

The above configuration would mean that the following URLs would be exposed:
 
* ``/prefix/profiles/avatar/1.png?config=CONFIG``
* ``/prefix/profiles/background/1.jpg?config=CONFIG``
