Handlebars.js in Django templates - django

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.

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.

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 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:
create HB template under
appdirectory/hbtemplates/myapp/template.html
(just like Django template)
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

Related

VSCode breaks Django template tags with newline

Problem:
{% extends 'base.html' %} {% block title %} Dashboard {% endblock %} {% block pagetitle %}
becomes
{% extends 'base.html' %} {% block title %} Dashboard {% endblock %} {% block
pagetitle %}
Note that the {% tag %} is being broken with a new line. This causes syntax errors with django templates.
I've tried most top django template extensions and this does not fix the issue.
I've also tried these settings:
"[html]": {
"editor.formatOnSave": false,
},
"html.format.wrapLineLength": 0,
"html.format.enable": false,
"prettier.disableLanguages": ["html"]
Desired Behavior:
Automatically format *.html files, while preserving django template tags, not breaking them up with newlines.
Sub-optimal (but acceptable) behavior: don't format *.html files at all.
I had the same issue and the only way I found that solved it is to disable the default HTML formatter. Unfortunately, I did not find a way to make it format Django template tags correctly. You can do the same if you go to VS Code Preferences > Settings > User > Extensions > HTML and uncheck 'Enable/disable default HTML formatter'.
I solved this by following this advice: https://stackoverflow.com/a/73892745/1257347
TLDR: install the djLint extension (and remember to do $ pip install djlint)
I got it to work by simply adding {{""}} between the {% tag %} that were being broken.
Example:
{% extends 'main/base.html' %} {% block title_block %}Homepage{% endblock%}
{{""}} {%block style_ref_block%}{%endblock%} {{""}} {% block body_block %}
This Didn't work for me.
The hack I found was to set the vscode language to jinja instead of the auto detected html
reference
I've also just experienced vs-code misbehaving on django template tags (i.e. deleting curly braces).
I don't like the idea of disabling HTML formatting just to support templates (i.e. vs-code Preferences/Settings/Extensions/HTML: disable (uncheck) "HTML>Format:Enable"). This is arguably a step backwards, but it does stop vs-code misbehaving.
Instead, I chose to install (vs-code Preferences/Extensions) the 'Django' extension, by Baptiste Darthenay. This was a better way to go, because it works, gracefully, preserves native vs-code HTML formatting, and includes a nice set of django snippits, which saves me keystrokes when embedding template code. Tada!
BTW, before finding Baptiste's awesome extension, I also tried keeping vs-code HTML formatting enabled, AND enabling 'HTML>Format:Templating', which promised to "Honor django and other templating language tags"; it did not.

How to use Django template tag within another tag?

I have a Django website that I'm trying to get internationalized. The image files are all encoded with the language code of two letters. So when a user switches the language, the references to image files are updated with the language code in templates as follows:
<img src="{% static 'website/images/contact_us_{{ LANGUAGE_CODE }}.png' %}">
Problem is, I have to have a tag as well for the path of static content. What is an elegant way to solve this?
Per #MarAja suggestion, I followed his/her question and solution here which was practically identical to mine. I'm posting what I did, so whoever that lands on this page has a solution. During my research, I did not stumble upon #MarAja's post.
The code is an exact copy, and the choice not to use add tag is because according to the Django documentation, it tries to cast the arguments to an int i.e. not intended for strings.
Full code:
# Custom Template tag file named "custom_app_tags.py"
from django import template
register = template.Library()
#register.filter
def addstr(s1, s2):
return str(s1) + str(s2)
Finally, usage:
{% load staticfiles %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% load custom_app_tags %}
<img src="{% static 'website/images/contact_us_'|addstr:LANGUAGE_CODE|addstr:'.png' %}">
Note, I included everything so that whomever gets here later, gets a complete picture of what is going on.

Using AngularJS template tags in Django [duplicate]

I want to use AngularJS with Django however they both use {{ }} as their template tags. Is there an easy way to change one of the two to use some other custom templating tag?
For Angular 1.0 you should use the $interpolateProvider apis to configure the interpolation symbols: http://docs.angularjs.org/api/ng.$interpolateProvider.
Something like this should do the trick:
myModule.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
});
Keep in mind two things:
mixing server-side and client-side templates is rarely a good idea and should be used with caution. The main issues are: maintainability (hard to read) and security (double interpolation could expose a new security vector - e.g. while escaping of serverside and clientside templating by themselves might be secure, their combination might not be).
if you start using third-party directives (components) that use {{ }} in their templates then your configuration will break them. (fix pending)
While there is nothing we can do about the first issue, except for warning people, we do need to address the second issue.
you can maybe try verbatim Django template tag
and use it like this :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
{% verbatim %}
<div ng-app="">
<p>10 is {{ 5 + 5 }}</p>
</div>
{% endverbatim %}
If you did separate sections of page properly then you can easily use angularjs tags in "raw" tag scope.
In jinja2
{% raw %}
// here you can write angularjs template tags.
{% endraw %}
In Django template (above 1.5)
{% verbatim %}
// here you can write angularjs template tags.
{% endverbatim %}
We created a very simple filter in Django 'ng' that makes it easy to mix the two:
foo.html:
...
<div>
{{ django_context_var }}
{{ 'angularScopeVar' | ng }}
{{ 'angularScopeFunction()' | ng }}
</div>
...
The ng filter looks like this:
from django import template
from django.utils import safestring
register = template.Library()
#register.filter(name='ng')
def Angularify(value):
return safestring.mark_safe('{{%s}}' % value)
So I got some great help in the Angular IRC channel today. It turns out you can change Angular's template tags very easily. The necessary snippets below should be included after your angular include (the given example appears on their mailing lists and would use (()) as the new template tags, substitute for your own):
angular.markup('(())', function(text, textNode, parentElement){
if (parentElement[0].nodeName.toLowerCase() == 'script') return;
text = text.replace(/\(\(/g,'{{').replace(/\)\)/g, '}}');
textNode.text(text);
return angular.markup('{{}}').call(this, text, textNode, parentElement);
});
angular.attrMarkup('(())', function(value, name, element){
value = value.replace(/\(\(/g,'{{').replace(/\)\)/, '}}');
element[0].setAttribute(name, value);
return angular.attrMarkup('{{}}').call(this, value, name, element);
});
Also, I was pointed to an upcoming enhancement that will expose startSymbol and endSymbol properties that can be set to whatever tags you desire.
I vote against using double parentheses (()) as template tag. It may work well as long as no function call is involved but when tried the following
ng:disabled=(($invalidWidgets.visible()))
with Firefox (10.0.2) on Mac I got a terribly long error instead of the intended logic. <[]> went well for me, at least up until now.
Edit 2012-03-29:
Please note that $invalidWidgets is deprecated. However I'd still use another wrapper than double braces. For any angular version higher than 0.10.7 (I guess) you could change the wrapper a lot easier in your app / module definition:
angular.module('YourAppName', [], function ($interpolateProvider) {
$interpolateProvider.startSymbol('<[');
$interpolateProvider.endSymbol(']>');
});
API docs.
You could always use ng-bind instead of {{ }}
http://docs.angularjs.org/api/ng/directive/ngBind
<span ng-bind="name"></span>
I found the code below helpful. I found the code here: http://djangosnippets.org/snippets/2787/
"""
filename: angularjs.py
Usage:
{% ng Some.angular.scope.content %}
e.g.
{% load angularjs %}
<div ng-init="yourName = 'foobar'">
<p>{% ng yourName %}</p>
</div>
"""
from django import template
register = template.Library()
class AngularJS(template.Node):
def __init__(self, bits):
self.ng = bits
def render(self, ctx):
return "{{%s}}" % " ".join(self.ng[1:])
def do_angular(parser, token):
bits = token.split_contents()
return AngularJS(bits)
register.tag('ng', do_angular)
If you use django 1.5 and newer use:
{% verbatim %}
{{if dying}}Still alive.{{/if}}
{% endverbatim %}
If you are stuck with django 1.2 on appengine extend the django syntax with the verbatim template command like this ...
from django import template
register = template.Library()
class VerbatimNode(template.Node):
def __init__(self, text):
self.text = text
def render(self, context):
return self.text
#register.tag
def verbatim(parser, token):
text = []
while 1:
token = parser.tokens.pop(0)
if token.contents == 'endverbatim':
break
if token.token_type == template.TOKEN_VAR:
text.append('{{')
elif token.token_type == template.TOKEN_BLOCK:
text.append('{%')
text.append(token.contents)
if token.token_type == template.TOKEN_VAR:
text.append('}}')
elif token.token_type == template.TOKEN_BLOCK:
text.append('%}')
return VerbatimNode(''.join(text))
In your file use:
from google.appengine.ext.webapp import template
template.register_template_library('utilities.verbatim_template_tag')
Source:
http://bamboobig.blogspot.co.at/2011/09/notebook-using-jquery-templates-in.html
You can tell Django to output {{ and }}, as well as other reserved template strings by using the {% templatetag %} tag.
For instance, using {% templatetag openvariable %} would output {{.
I would stick with a solution that uses both django tags {{}} as well angularjs {{}} with a either a verbatim section or templatetag.
That is simply because you can change the way angularjs works (as mentioned) via the $interpolateProvider.startSymbol $interpolateProvider.endSymbol but if you start to use other angularjs components like the ui-bootstrap you will find that some of the templates are ALREADY built with standard angularjs tags {{ }}.
For example look at https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html.
If you do any server-side interpolation, the only correct way to do this is with <>
$interpolateProvider.startSymbol('<{').endSymbol('}>');
Anything else is an XSS vector.
This is because any Angular delimiters which are not escaped by Django can be entered by the user into the interpolated string; if someone sets their username as "{{evil_code}}", Angular will happily run it. If you use a character than Django escapes, however, this won't happen.

Django template variable containing template tag, ex {{ {% some_tag %} }}

I have a template that receives a list context variable, tags_list. I need to iterate over this list 'inserting' the tags in the template something like this:
{% for tag in tags_list %}
{{ tag.tag }}
{% endfor %}
When this renders it returns the text value of tag.tag, "{% tagxxx %}", not the rendered tag.
How can I cause the template render to render the value of a context variable? Alternately, is there a filter, a sort of inverse verbatim, that will cause the value of a context variable to be rendered?
Updated background
tags_list is created by a fairly sophisticated process involving exec of some user provided text from a table/model field. The relevant portion of the real template looks like this:
{% for graph_row in graph_rows %}
<div class="row">
{% for graph in graph_row %}
<div class="col-md-{{ graph.width }}">
{{ graph.graph }}
</div>
{% endfor %}
</div>
{% endfor %}
The graph values look like this: {'graph':'{% piechart data1 %}', 'width':3}
Note that the order of entries in the context variable graph_rows is significant as is order of graph(s) in the row as that determines the placement of graphs on the page. Preserving this order is essential for the scheme to work correctly.
Currently, the view function simply does an {% include ... %} to get the template segment above to render in the correct order. This approach is simple and clean.
I could, as has been suggested, perform a template render within the view function but that complicates the design a bit and I'd hoped to avoid doing that if there is an easy way to trigger a render of {{ graph.graph }}. Note, as well, by moving the render into the view I loose the ability to easily take the template from arbitrary places, in particular table fields.
One of the great things about Django is the library of solution and code snippets. Sadly, they aren't a well organized and easy to find as one might wish. Nevertheless, a bit of google found a number of solutions of the general form
{% render tag.tag %}
Here are links to several:
render_as_template template tag
Allow template tags in a Flatpage's content
render_as_template.py
I'll use the general approach cleaned up a bit for error checking.
As an aside, the technique strikes me as generally useful and might be appropriate for inclusion in the standard tags.
Update 3/28/2014
After looking at the above and several others this is what I used from render_as_template template tag. There is a useful comment here.
from django import template
from django.template import Template, Variable, TemplateSyntaxError
register = template.Library()
class RenderAsTemplateNode(template.Node):
def __init__(self, item_to_be_rendered):
self.item_to_be_rendered = Variable(item_to_be_rendered)
def render(self, context):
try:
actual_item = self.item_to_be_rendered.resolve(context)
return Template(actual_item).render(context)
except template.VariableDoesNotExist:
return ''
def render_as_template(parser, token):
bits = token.split_contents()
if len(bits) !=2:
raise TemplateSyntaxError("'%s' takes only one argument"
" (a variable representing a template to render)" % bits[0])
return RenderAsTemplateNode(bits[1])
render_as_template = register.tag(render_as_template)
This gets part of the way to a solution. Unfortunately custom template tags, in my case
{% pie_chart %} are not available to render within the class RenderAsTemplateNode.
I've not tested this but it appears that this stack overflow question, Django - replacing built-in templatetag by custom tag for a whole site without {% load .. %}, points the way.
I believe I can provide a way for you to get the results you want, but there might be a better way for you to achieve the desired functionality if you can provide some context.
Anyway, you might do something like this in your view.py:
tags_list = [
Template('{% load my_tags %}{% ' + t.tag + ' %}').render(Context())
for t in tags_list
]

Django Custom Inclusion Tags

I'm trying to build my own template tags.
I have no idea why I getting these errors. I'm following the Django doc's.
This is my app's file structure:
pollquiz/
__init__.py
show_pollquiz.html
showpollquiz.py
This is showpollquiz.py:
from django import template
from pollquiz.models import PollQuiz, Choice
register = template.Library()
#register.inclusion_tag('show_pollquiz.html')
def show_poll():
poll = Choice.objects.all()
return { 'poll' : poll }
html file:
<ul>
{% for poll in poll
<li>{{ poll.pollquiz }}</li>
{% endfor
</ul>
in my base.html file im am including like this
{% load showpollquiz %}
and
{% poll_quiz %}
Bu then I get the the error:
Exception Value: Caught an exception while rendering: show_pollquiz.html
I have no idea why this happens. Any ideas? Please keep in mind I'm still new at Django
Shouldn't all custom filters be inside the templatetags directory?
templatetags/
__init__.py
showpollquiz.py
then
#register.inclusion_tag('show_pollquiz.html')
looks in MY_TEMPLATE_DIR/show_pollquiz.html for the template
You forgot to close your template tags... Also, you should change the name in the for tag, you can't have for poll in poll:
<ul>
{% for p in poll %} <!--here-->
<li>{{ p.pollquiz }}</li>
{% endfor %} <!--and here-->
</ul>
Also notice you're not using the inclusion tag you defined at all. I think you got some code mixed up, try to go over a tutorial start to end and things will be clearer.
I'd not bother with writing your own template tags: take things one step at a time and stick to the basics for now. There's nothing wrong with {% include 'show_pollquiz.html' %}
I found the problem. The problem was that the #register.inclusion_tag('show_pollquiz.html')
inclusion tag is obviously looking for the template in the default_template directory. So that is why i got the error.
According to me this is not clear in the documentation. But I guess its how it is, being a template and all...
Oh , well.
Now, how would I put the #register.inclusion_tag('show_pollquiz.html') to look in the same folder as the app? under templatetags/?