Skip to main content

A Django template tag for embedding Mustache.js templates safely.

Project description

=================
django-mustachejs
=================

|build status|_

.. |build status| image:: https://secure.travis-ci.org/mjumbewu/django-mustachejs.png
.. _build status: https://secure.travis-ci.org/mjumbewu/django-mustachejs

A templatetag for easier integration of `mustache.js`_ JavaScript templates with
Django templates. Inspired by `ICanHaz.js`_, `django-icanhaz`_, and
`jquery.mustache`_.

.. _mustache.js: http://mustache.github.com/
.. _django-icanhaz: http://github.com/carljm/django-icanhaz
.. _ICanHaz.js: http://icanhazjs.com/
.. _jquery.mustache: https://github.com/AF83/jquery.mustache

Quickstart
==========

Dependencies
------------

Tested with `Django`_ 1.3 through trunk, and `Python`_ 2.6 and 2.7. Almost
certainly works with older versions of both.

.. _Django: http://www.djangoproject.com/
.. _Python: http://www.python.org/

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

Install from PyPI with ``pip``::

pip install django-mustachejs

or get the `in-development version`_::

pip install django-mustachejs==dev

.. _in-development version: https://github.com/mjumbewu/django-mustachejs/tarball/develop#egg=mustachejs

Usage
-----

* Add ``"mustachejs"`` to your ``INSTALLED_APPS`` setting.

* Set the ``MUSTACHEJS_DIRS`` setting to a list of full (absolute) path to
directories where you will store your mustache templates. By default this is
set to a directory named ``jstemplates``.

* Set the ``MUSTACHEJS_EXTS`` setting to a list of the app should search for
to find template files. By default this is set to ``['mustache', 'html']``.
Order matters (e.g., ``*.mustache`` will take precedence over ``*.html``).

* In your HTML header, include ``mustache/js/mustache-<version>.js``. The
versions shipped with django-mustache are ``0.3.0`` and ``0.4.0-dev``.

* ``{% load mustachejs %}`` and use ``{% mustachejs "templatename" %}`` in your
Django templates to safely embed the mustache.js template at
``<MUSTACHEJS_DIRS-entry>/templatename.html`` into your Django template. It
will be stored in the ``Mustache.TEMPLATES`` object as a string, accessible
as ``Mustache.TEMPLATES.templatename``.

* In your JavaScript, use
``Mustache.to_html(Mustache.TEMPLATES.templatename, {...}, Mustache.TEMPLATES)``
to render your mustache template. Alternatively, if you include the
``mustache/js/django.mustache.js`` script in your HTML, you can use
``Mustache.template('templatename').render({...})`` to render your mustache
template.


An Example
----------

For example consider the files ``app/jstemplates/main.mustache``::

<div>
<p>This is {{ name }}'s template</p>
</div>

and ``app/templates/main.html``::

{% load mustachejs %}

<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>

<script src="{{ STATIC_URL }}mustache/js/mustache-0.3.0.js"></script>
<script src="{{ STATIC_URL }}mustache/js/django.mustache.js"></script>
</head>

<body>
<div id="dynamic-area"></div>

{% mustachejs "main" %}

<script>
$(document).ready(function() {

var $area = $('#dynamic-area')
, template;

// Either render by accessing the TEMPLATES object
// directly...

$area.html(Mustache.to_html(Mustache.TEMPLATES.main));

// ...or render by using a cached template object
// (requires django.mustache.js)

template = Mustache.template('main');
$area.html(template.render());

});
</script>
</body>
</html>

What's going on?
----------------

Any time you use the ``mustachejs`` template tag::

{% load mustachejs %}
{% mustachejs "main" %}

django-mustachejs will generate the following::

<script>Mustache.TEMPLATES=Mustache.TEMPLATES||{};Mustache.TEMPLATES['main']='<div>\n <p>This is {{ name }}\'s template</p>\n</div>';</script>

This stores the text of the template in an attribute on the ``Mustache.TEMPLATES``
object (it will first create the object if it does not yet exist). The
``Mustache.template(...)`` function then creates an object with a ``render(...)`` method
that has a similar signature as ``Mustache.to_html(...)``, except without the template
name as the first parameter. The ``render`` method will also use the set of templates
in ``Mustache.TEMPLATES`` as partials, allowing any template that django-mustachejs
knows about to be used as a template partial as well.

Regular Expressions in Template Tags
------------------------------------

Using the template tag ``{% mustachejs [directory] [regex] %}`` in your
Django templates will embed all files matching that regex in the given
directory. So, ``{% mustachejs './' '.*_template' %}`` would match
`note_template.html` and `comment_template.html`, giving them templatename
`note_template` and `comment_template`, respectively. (Note that the ".html"
extension is assumed. See the advanced usage section for how to customize
this behavior).

Internationalization (i18n)
---------------------------

django-mustachejs supports internationalization tags. In your settings module,
set the ``MUSTACHEJS_I18N_TAGS`` variables (default: ``('_', 'i18n')``). These
tags can be used to preprocess the javascript templates into translatable
content. For example::

<div>{{#_}}Hello, {{name}}. I like your {{color}} {{thing}}?{{/_}}</div>

may render to::

<div>Salut, {{name}}. J'aime votre {{thing}} {{color}}?</div>

The translatable strings will be picked up by Django's ``makemessages``
management command.

Advanced usage
--------------

You can also bundle MustacheJS templates with Django reusable apps; by default
``django-mustache`` will look for templates in a ``jstemplates`` subdirectory of
each app in ``INSTALLED_APPS``. The app subdirectory name(s) to check can be
configured via the ``MUSTACHEJS_APP_DIRNAMES`` setting, which defaults to
``["jstemplates"]``.

The finding of templates can be fully controlled via the ``MUSTACHEJS_FINDERS``
setting, which is a list of dotted paths to finder classes. A finder class
should be instantiable with no arguments, and have a ``find(name)`` method
which returns the full absolute path to a template file, given a base-name.

Regex finding of templates can be fully controlled via the
``MUSTACHEJS_REGEX_FINDERS`` setting. A regex finder class should be
instantiable with no arguments and have a ``find(dir, regex)`` method
which takes in two strings (directory and regex) and returns a list of
matches in the form `[(name, filepath)...]` where name is the id given
to a template and filepath is a full absolute path to a template file.

By default, ``MUSTACHEJS_FINDERS`` contains ``"mustachejs.finders.FilesystemFinder"``
(which searches directories listed in ``MUSTACHEJS_DIRS``) and
``"mustachejs.finders.AppFinder"`` (which searches subdirectories named in
``MUSTACHEJS_APP_DIRNAMES`` of each app in ``INSTALLED_APPS``), in that order --
thus templates found in ``MUSTACHEJS_DIRS`` take precedence over templates in
apps.

By default, ``MUSTACHEJS_REGEX_FINDERS`` contains
``"mustachejs.finders.FilesystemRegexFinder"` (which searches directories listed
in ``MUSTACHEJS_DIRS``) and ``"mustachejs.finders.AppRegexFinder"`` (which searches
subdirectories named in ``MUSTACHEJS_APP_DIRNAMES`` of each app in
``INSTALLED_APPS``). Precedence is unimportant, as all matching templates
are added. Further, django-mustachejs is bundled with two convenience scoping
regex finders: ``mustachejs.finders.ScopedFilesystemRegexFinder`` and
``mustachejs.finders.ScopedAppRegexFinder`` which each prepend a scope derived
from the directory path given to each name: so, if
``{% mustachejs './all/my/templates/' '.*_template' %}` matches
`note_template.html` and `comment_template.html`, they will have names
`all_my_templates_note_template` and `all_my_templates_comment_template`,
respectively.


Rationale (from `django-icanhaz`_)
----------------------------------

The collision between Django templates' use of ``{{`` and ``}}`` as template
variable markers and `mustache.js`_' use of same has spawned a variety of
solutions. `One solution`_ simply replaces ``[[`` and ``]]`` with ``{{`` and
``}}`` inside an ``mustachejs`` template tag; `another`_ makes a valiant attempt
to reconstruct verbatim text within a chunk of a Django template after it has
already been mangled by the Django template tokenizer.

I prefer to keep my JavaScript templates in separate files in a dedicated
directory anyway, to avoid confusion between server-side and client-side
templating. So my contribution to the array of solutions is essentially just an
"include" tag that avoids parsing the included file as a Django template (and
for convenience, automatically wraps it in the script tag that `ICanHaz.js`_
expects to find it in).

Enjoy!

.. _one solution: https://gist.github.com/975505
.. _another: https://gist.github.com/629508


CHANGES
=======

0.7.4
------------------

* Fix i18n preprocessor for python 2.6 compatibility

0.7.3
------------------

* Correctly escaped translated strings.

0.7.2
------------------

* Changed search pattern to be non-greedy.

0.7.1
------------------

* Handle translation strings with new lines.

0.7.0
------------------

* Pulled in commit from django-icanhaz to load templates using regular
expressions.

* Added preprocessing framework, and a preprocessor for i18n.

* Hijack the makemessages command to find js template messages as well.

0.6.0
------------------

* Add ``dustjs`` tag to insert a script block to create a compiled dustjs
template. Thanks to `Gehan Gonsalkorale <https://github.com/gehan>`_.

0.5.0
------------------

* Add ``mustacheraw`` tag to insert just the raw text of a mustacehe template.
Thanks to Greg Hinch.

* Add ``mustacheich`` tag to insert a mustache script block as icanhaz expects.

0.4.1 (2012.01.09)
------------------

* Fixed template reading to explicitly decode template file contents using
Django's ``FILE_CHARSET`` setting. Thanks Eduard Iskandarov.

* Fixed template-finding failure with non-normalized directories in
``MUSTACHEJS_DIRS``. Thanks Eduard Iskandarov for report and patch.


0.4.0
------------------

* Add the MUSTACHEJS_EXTS configuration variable for specifying the extensions
allowed for template files located by the FilesystemFinder (and, by extension,
the AppFinder).


0.3.3
------------------

* Add a package_data value to the setup call


0.3.2
------------------

* Add the MANIFEST.in file itself as an entry in MANIFEST.in.


0.3.0
------------------

* Change the name from django-icanhaz to django-mustachejs.
* Remove dependency on ICanHaz.js. I like the library, but the maintainers
were not responsive enough for now. Use Mustache.js straight, with a little
bit of minimal sugar. Templates are rendered to straight Javascript.


0.2.0 (2011.06.26)
------------------

* Made template-finding more flexible: ``ICANHAZ_DIR`` is now ``ICANHAZ_DIRS``
(a list); added ``ICANHAZ_FINDERS``, ``ICANHAZ_APP_DIRNAMES``, and finding of
templates in installed apps.


0.1.0 (2011.06.22)
------------------

* Initial release.


TODO
====

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-mustachejs-0.7.4.tar.gz (20.0 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page