Mustache templates in Django (with i18n support)
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Inspired by ctemplate and et, Mustache is a framework-agnostic way to render logic-free views.

As ctemplates says, "It emphasizes separating logic from presentation: it is impossible to embed application logic in this template language."

Pystache is a Python implementation of Mustache. Pystache requires Python 2.6.


The different Mustache tags are documented at mustache(5).

Install It

git clone
cd django-pystache
python build
python install

Use It

>>> import pystache
>>> pystache.render('Hi {{person}}!', {'person': 'Mom'})
'Hi Mom!'

You can also create dedicated view classes to hold your view logic.

Here's your

import pystache
class Simple(pystache.View):
    def thing(self):
        return "pizza"

Then your template, simple.mustache:

Hi {{thing}}!

Pull it together:

>>> Simple().render()
'Hi pizza!'


The mustache spec does not have a tag for i18n. Support was later added to mustache.js by Twitter using the {{_i}}{{/i}} tags (see This fork adds the same feature to pystache. Check the examples/ file for more information.

If you use the "makemessages" django command, you may want to get the translation strings from your mustache templates. Copy the management directory in this repository to your apps' directory and issue the makemessages command as usual with the additional "-e .mustache" parameter. Example:

python ../ makemessages -l pt_PT -e .mustache

Keep in mind that, at this moment, translation blocks must not include other block tags. For example, this does not work:

{{_i}}{{name}} is using mustache.js!{{/i}}

You can also pre-render translations in the server by using the "pre_render_i18n" method. Check the example below.


# views/
from django.utils import simplejson as json
from django.http import HttpResponse
import pystache

pystache.View.template_path = relative('..', 'templates') # Define where the templates are kept
pystache.View.template_encoding = 'utf8' # Define encoding

class View(pystache.View):
    ''' Main View class '''
    def __init__(self, *args):
        super(View, self).__init__()
        ... # Set common local variables, layout, ...

    def template(cls, request, **args):
        ''' Return raw template '''
        template = pystache.Loader().load_template(cls.template_name, cls.template_path)
        return HttpResponse(template)

    def template_pre_rendered(cls, request, **args):
        ''' Return raw template with pre-rendered translation sections '''
        template = pystache.Loader().load_template(cls.template_name, cls.template_path)
        template = pystache.Template(template).pre_render_i18n() # Pre-render translation sections
        return HttpResponse(template)

    def json(cls, request, **args):
        ''' Return data to render template on the client-side '''
        view = cls(request, **args)
        return HttpResponse(json.dumps(vars(view)), 'application/json')

# views/
class Edit(View):
    ''' Example View class '''
    template_path = os.path.join(pystache.View.template_path, 'users')

    def __init__(self, *args):
        super(Edit, self).__init__()
        ... # Set local variables

    def view(cls, request, **args):
        ''' Return the rendered page '''
        view = cls(request, **args)
        ... # Do stuff
        return HttpResponse(view.render())

urlpatterns = patterns('',
    url(r'^user/edit$',           users.Edit.view),
    url(r'^user/edit\.mustache$', users.Edit.template_pre_rendered),
    url(r'^user/edit\.json$',     users.Edit.json),

# locale/.../django.po
#: templates/users/edit.mustache:18
msgid "My internationalized string!"
msgstr "A minha string traduzida!"

Test It

nose works great!

pip install nose
cd pystache


  • Create an example Django project
  • Add tests for internationalization


context = { 'author': 'Chris Wanstrath', 'email': '' }
pystache.render("{{author}} :: {{email}}", context)


Original "makemessages" command reimplementation by altunyurt (djtemps project)

Inspiration from jhurt (pystache fork)