"... and no one shall work for money, and no one shall work for fame; But each for the joy of the working, and each, in his separate star, shall draw the thing as he sees it, for the god of things as they are"

-Kipling

 

Getting Django JSTemplate and Mustache to Work

Summary

Here is the situation: you want to use the Moustache templating engine in Django and are having trouble getting it to work. The online documentation on the topic seems very thorough but you are having configuration issues which are causing problems and nothing works. The primary source of this issue is that the documentation assumes a lot of knowledge, the lack of which which can cause those inexperienced with Django and JavaScript/Moustache considerable trouble. This note is an attempt to fill in the blanks in the documentation with novice friendly advice and is basically the information that I would have liked to have had available when I was trying to get the django-jstemplate app working.

Below are some error messages you may be seeing - all of these have to be resolved or the templating engine will not work. Note: On this page, and in the messages below, the text "ABC" is the name of the Django app the engine is working on - consider it to be a placeholder for your app name.

So, lets take them one issue at a time and find out what is going on.

What's the Point of django-jstemplate

Be aware that installing django-jstemplate does not give you the mustache.js code. You still have to include that script in your Django page template. All the django-jstemplate app is really doing is providing you with the functionality that will allow you to access the mustache templates in a nice Django'ish way.

To get the mustache.js code, the file you want is mustache.min.js and there are several ways to introduce this into your web page.

 <script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
    

The Older django-mustachejs is Now Named django-jstemplate

Let's clarify what this page is discussing (and what you may be working with). The django-mustachejs app has been renamed to django-jstemplate. Other than the usual minor upgrade sort of stuff they both serve exactly the same purpose and do exactly the same thing.

Be aware of which app you are working with and especially be aware that this name change also introduces a number of important configuration changes to your settings.py file (and others). A lot of the documentation you may read on the Internet will be discussing the configuration for django-mustachejs. The migration is simple - but when debugging it is important to be aware of what app you are actually using.

Install the django-jstemplate app by running something like the following:

  pip install django-jstemplate
If you have installed django-mustachejs you may wish to run a command like the following to remove it:
  pip uninstall django-mustachejs
Check your settings.py file and your Django templates. Here is a summary of the name changes If you wish to continue using the older django-mustachejs then a lot of the information on this page will still be useful but you are going to have to translate some of the settings.py code.

Check the INSTALLED_APPS section of your settings.py File.

The INSTALLED_APPS section of your settings.py should have a line in it that looks like:

  'jstemplate',

Set up the JSTEMPLATE_DIRS section of your settings.py File.

The JSTEMPLATE_DIRS section of your settings.py should point at the directories in which your templates are located:

JSTEMPLATE_DIRS = [
    os.path.join(BASE_DIR, 'ABC/jstemplates/ABC'),
]
Of course, the path can be whatever you wish and you can have multiple entries (one per line) for different apps. It works similar to the STATICFILES_DIRS setting with one important exception. You can NOT us the BASE_DIR construct in JSTEMPLATE_DIRS in the way you do in the STATICFILES_DIRS section. For example, the code below will generate an error of TypeError at /ABC/ object of type 'WindowsPath' has no len(). The django-jstemplate code that parses the JSTEMPLATE_DIRS section simply is not that clever.
JSTEMPLATE_DIRS = [
    BASE_DIR / "ABC/templates/ABC",                     # do NOT do this
    os.path.join(BASE_DIR, 'ABC/jstemplates/ABC'),      # do it this way
]

Set up the JSTEMPLATE_EXTS section of your settings.py File.

The JSTEMPLATE_EXTS section of your settings.py tells the django-jstemplate app what file name extensions to look for. By default ".mustache" and ".html" are used. The django-jstemplate app will pick up both of these unless you tell it otherwise. Personally, I don't like my mustache template files to be ".html" as think it should be obvious what they are. Of course, if that doesn't bother you then you can ignore this section. An example JSTEMPLATE_EXTS section might look like:

JSTEMPLATE_EXTS = [
    'mustache',
]

Add a FILE_CHARSET section to your settings.py File.

Your settings.py needs a line detailing the character set of the files it will be opening. This is actually an older, deprecated, Django setting and is not really a django-jstemplate thing. The problem is that because Django assumes UTF-8 by default, many settings.py files do not contain this information. The django-jstemplate app does not assume that default and so you must specify it or you will get an error like: ImproperlyConfigured at /ABC/ FILE_CHARSET setting is required. Below is an example -just add it to your settings.py and you will fix the problem:

FILE_CHARSET = 'utf-8'

Add a {% load jstemplate %} line to your Django Template File.

Your Django template file (the HTML file) needs a line loading the jstemplate app. If it is not present you will get an error like: Invalid block tag on line xx: 'mustachejs', expected 'endblock'. Did you forget to register or load this tag. Below is an example of the top of a Django template with the appropriate line included:

{% extends "ABC/ABC_base.html" %}
{% load static %}
{% load jstemplate %}
{% load ABC_tags %}
Of course, you also need the mustache.min.js engine available on the page. See the section above that discusses this.

Load your Mustache Template

At last we get to the actual usage of Mustache to load HTML templates. The template can be loaded by placing a line like the one below in the body of the HTML on the page.

{% mustachejs "test1" %}
If the configuration of the settings.py file is correct and you have a file named test1.mustache in one of the directories pointed at by the JSTEMPLATE_DIRS setting, the file should load. At this point the text is just un-rendered HTML markup and it will be stored in the Mustache.TEMPLATES object as a string. The text of the test1.mustache file will be accessible as Mustache.TEMPLATES.test1. If the template cannot be found you will see an error like: JSTemplateNotFound at /ABC/.

For debugging purposes you can check the content is present by setting up something like the following in JavaScript:

<script>
$(document).ready(function() {
    alert(Mustache.TEMPLATES.test1);
}); 
<script> 

Render the Mustache Template and Include it on the Page

Following the online documentation for the django-jstemplate app, let us assume the HTML on the page contains an element like:

<div id="dynamic-area"></div>
Furthermore, lets assume the content of the test1.mustache file is as shown below:
<div>
  <p>This is {{ name }}'s template</p>
</div>
Down in our JavaScript we can render and insert the text as follows (this assumes the test1.moustache file has previously been loaded):
<script>
$(document).ready(function() {
        var dataObj = {
        name : "Joe",
        };
        var $area = $('#dynamic-area');
        $area.html(Mustache.to_html(Mustache.TEMPLATES.test1, dataObj));
}); 
<script> 
This will replace substitute in the {{ name }}variable and the inner HTML content of the DIV element with the id of dynamic-area will get rendered text like ...
<div>
This is Joe's template
</div>
... and you should see something like "This is Joe's template" appear on the web page. The problem here is that the example in the online documentation does not pass in an object which has a name field. This is shown below:
<script>
$(document).ready(function() {
        var $area = $('#dynamic-area');
        $area.html(Mustache.to_html(Mustache.TEMPLATES.test1));
}); 
<script> 
The above code will generate an error of mustache.min.js:1 Uncaught TypeError: Cannot read property 'name' of undefined. All that is really happening here is that there is no object with a name field for the mustache.js software to substutute. Easy enough to fix - but the error message is not so simple for the inexperienced to interpret.

The Alternative Mustache Template Render Method

The online documentation also illustrates another method of rendering the template text. It looks something like the code shown below:

<script>
$(document).ready(function() {
      var template = Mustache.template('test1');
      $area.html(template.render());
}); 
<script> 
This appears to generate an error of Uncaught TypeError: Mustache.template is not a function . I am not at all sure of what is going on here and (to be honest) I don't much care. The previous Mustache.to_html method is sufficient for my needs and I did not put much time into trying to resolve this error.

License

The contents of this web page are provided "as is" without any warranty of any kind and without any claim to accuracy. Please be aware that the information provided may be out-of-date, incomplete, erroneous or simply unsuitable for your purposes. Any use you make of the information is entirely at your discretion and any consequences of that use are entirely your responsibility. All source code is provided under the terms of the MIT License.