English 中文(简体)
Handlebars.js in Django templates
原标题:

I need a javascript templating system and i think handlebars.js does an excellent job in this case. I m having syntax conflicts with handlebars templates inside a django template because django tries to render handlebars variables.

Is there a tag in django templates to stop rendering a block with curly braces?

Something like:

{{ django_context_varable }} #works
{{% raw %}}
<script id="restaurants-tpl" type="text/x-handlebars-template">
    <ul>
    {{#restaurants}} #not rendered by django, plain text
    <li>{{name}}</li>
    {{/restaurants}}
    </ul>
</script>
{{% endraw %}}

Edit

Likely i found this. It works fine.

Update

Django 1.5 supports verbatim tag natively.

最佳回答

Is there a tag in django templates to stop rendering a block with curly braces?

OLD Answer for Django 1.0-1.4: No, though you could though you could put the block in a separate file and include it without rendering or use a different templating engine.

New Answer: The answer above was correct in August 2011 when the question was asked and answered. Starting in Django 1.5 (released Feb 2013, though alpha/beta versions in late 2012), they introduced the {% verbatim %} and {% endverbatim %} which will prevent the django template engine from processing the content in the block.

So for the question asked the following will work in django 1.5+ out of the box:

{{ django_context_varable }} #works
{% verbatim %}
<script id="restaurants-tpl" type="text/x-handlebars-template">
    <ul>
    {{#restaurants}} #not rendered by django, plain text
    <li>{{name}}</li>
    {{/restaurants}}
    </ul>
</script>
{% endverbatim %}

The documentation on verbatim is here. Yes, this was noted by others earlier, but as this is the accepted answer I should list the easiest solution.

问题回答

I use a custom template tag for another js templating system, here: https://gist.github.com/629508

Use in template:

{% load mytags %}
{% verbatim %}
  {{ This won t be touched by {% django s %} template system }}
{% endverbatim %}

Edit: This custom template tag is no longer necessary, as Django s template language now supports the {% verbatim %} template tag.

I wrote a very small django application : django-templatetag-handlebars exactly for that purpose.

{% load templatetag_handlebars %}

{% tplhandlebars "tpl-infos" %}
    {{total}} {% trans "result(s)." %}
    <p>{% trans "Min" %}: {{min}}</p>
    <p>{% trans "Max" %}: {{max}}</p>
{% endtplhandlebars %}

Render your block as usual using Handlebars.js API :

var properties = {
    total: 10,
    min: 5,
    max: 4
};

var template = Handlebars.compile($( #tpl-infos ).html()),
    rendered = template(properties);

I wrote it the day @chrisv published its package, with a KISS approach in mind. It is mainly based on Miguel Araujo s gist : https://gist.github.com/893408.

for a deeper integration between handlebars and Django (including optional on-the-fly precompilation) check out my project at https://bitbucket.org/chrisv/django-handlebars/

It basically works like this:

  1. create HB template under

    appdirectory/hbtemplates/myapp/template.html
    

    (just like Django template)

  2. in your app, use

    {% handlebars myapp %} 
    

    template tag and render template like so:

    Handlebars.templates["myapp.template.html"]({context:"value"});
    

Compile your handlebars first!

From handlebars precompiling documentation:

In addition to reducing the download size, eliminating client-side compilation will significantly speed up boot time, as compilation is the most expensive part of Handlebars.

You can compile templates in your build environment using handlebars npm module, or integrate it with a build tool like gulp with gulp-handlebars.

After compiling, your handlebars templates can be served as static resources and bypass server side rendering altogether. Makes it easier on caching too :)

Typical usage would look like this:

<div id="restaurants-tpl">
    Waiting for content...
</div>

<script src="{% static  js/handlebars.runtime.js  %}"></script>
<script src="{% static  js/templates.js  %}"></script>
<script>
    // Let django render this as a json string
    properties = {{ properties }};

    // Use Handlebars compiled template imported above
    rendered_html = Handlebars.templates["restaurants-tpl"](properties);

    // Set element content 
    document.getElementById("restaurants-tpl").innerHTLM = rendered_html;
</script>

Django s templating system doesn t support escaping blocks at a time. It would be easy to work around were it not for the fact that when templates are processed the tokenizer doesn t keep exact information on what the tokens looked like before they got tokenized.

I have used the following work-around which is ugly, but (sort of) works. Use different tag delimiters in your templates and a django template tag that translates those back to what you actually want:

@register.tag(name="jstemplate")
def do_jstemplate(parser, token):
    while self.tokens:
        token = self.next_token()
        if token.token_type == TOKEN_BLOCK and token.contents == endtag:
            return
    self.unclosed_block_tag([endtag])
    nodelist = parser.parse( ( endjstemplate ,) )
    parser.delete_first_token()
    s = token.split_contents()
    tmpl_id = Variable( s[1] ) if (len(s) == 2 and s[1]) else   
    return JsTemplateNode( nodelist, tmpl_id )

class JsTemplateNode(template.Node):
    def __init__(self, nodelist, tmpl_id=  ):
        self.tmpl_id = tmpl_id
        self.nodelist = nodelist
    def render(self, context):
        content = self.nodelist.render(context)
        return u <script id="%s" type="text/x-handlebars-template">%s</script>  % (
                self.tmpl_id.resolve(context),
                re.sub( ur {$(.*?)$} , u {{\1}} , content ), )

For bonus points you can leverage Django s templates within your templates ... which will probably cook your brain trying to untangle later:

{% jstemplate "restaurants-tpl" %}
{$#restaurants$}
<div id="<$name$<" class="{$type$}">
    <ul class="info">
        {$#if info/price_range$}<li><em>{{ trans "Price Range" }}:</em> {$info/price_range$}</li>{$/if$}
        {$#if info/awards$}<li><em>{{ trans "Awards" }}:</em> {$info/awards$}{$/if$}
    </ul>
    <div class="options">
        <button>{% trans "Reservation" %}</button>
    </div>
</div>
{$/restaurants$}
{% jstemplate %}

Actually I wrote a custom template filter which goes like this:

from django import template
register = template.Library()
def handlebars(value):
    return  {{%s}}  % value
register.filter( handlebars , handlebars)

and use it in a template like so:

{{"this.is.a.handlebars.variable"|handlebars}}

It s the simplest thing I could think of. You just have to put your handlebars variable name in quotes. I regret I hadn t got this idea before I struggled with ssi. It works also with keywords:

{{"#each items"|handlebars}}

Why not use jinja2 instead? IMO, they re both elegant to use. Here s an excellent article about it: Using Jinja2 with Django





相关问题
How to get two random records with Django

How do I get two distinct random records using Django? I ve seen questions about how to get one but I need to get two random records and they must differ.

Moving (very old) Zope/Plone Site to Django

I am ask to move data from a (now offline) site driven by Plone to a new Django site. These are the version informations I have: Zope Version (unreleased version, python 2.1.3 ) Python Version 2.1....

Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

Flexible pagination in Django

I d like to implement pagination such that I can allow the user to choose the number of records per page such as 10, 25, 50 etc. How should I go about this? Is there an app I can add onto my project ...

is it convenient to urlencode all next parameters? - django

While writing code, it is pretty common to request a page with an appended "next" query string argument. For instance, in the following template code next points back to the page the user is on: &...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

热门标签