Django 模板中的 Handlebars.js

Posted

技术标签:

【中文标题】Django 模板中的 Handlebars.js【英文标题】:Handlebars.js in Django templates 【发布时间】:2011-11-05 23:12:56 【问题描述】:

我需要一个 javascript 模板系统,我认为 handlebars.js 在这种情况下做得很好。 我在 django 模板中与把手模板存在语法冲突,因为 django 尝试渲染把手变量。

django 模板中是否有一个标签来停止渲染带有花括号的块?

类似:

 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 %

编辑

我可能找到了this。它工作正常。

更新

Django 1.5 原生支持verbatim 标签。

【问题讨论】:

+1 用于更新逐字标记 我会预编译把手模板并将其用作静态资源:***.com/a/42636375/4326531 【参考方案1】:

我为另一个 js 模板系统使用自定义模板标签,这里: https://gist.github.com/629508

在模板中使用:

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

编辑:不再需要这个自定义模板标签,因为 Django 的模板语言现在支持 % verbatim % 模板标签。

【讨论】:

聪明的解决方案——一个块标签,它试图从解析的结构中重建原始结构。我不确定这是否适用于所有情况——例如,如果 django-POV 的模板中有错误,或者它使用了 % 之外的其他内容(例如,像 some_var|some_filter:"hello" 这样的过滤器)。虽然它很可能适用于必要的情况。 您是否在 django 1.4.1 上尝试过 gist 中的代码?实际上,我自己在一个微不足道的例子上遇到了麻烦,并且很好奇这是否仍然是一个合法的选择 逐字记录是在 DTL 1.5 中引入的。【参考方案2】:

django 模板中是否有一个标签来停止渲染带有花括号的块?

Django 1.0-1.4 的旧答案: No, 虽然您可以将块放在单独的文件中并包含它而不渲染或使用不同的模板引擎。

新答案:上述答案在 2011 年 8 月被提问和回答时是正确的。从 Django 1.5(2013 年 2 月发布,虽然 2012 年底的 alpha/beta 版本)开始,他们引入了 % verbatim %% endverbatim %,这将阻止 django 模板引擎处理块中的内容。

所以对于提出的问题,以下内容将在 django 1.5+ 中开箱即用:

 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 %

verbatim is here 上的文档。是的,其他人之前已经注意到了这一点,但由于这是公认的答案,我应该列出最简单的解决方案。

【讨论】:

% include_raw % 自定义标签似乎是最好的选择。 % ssi % 做同样的事情(如 % include_raw %)并且它已经在标准中 对于较新版本的 Django,请确保仅使用单个大括号标签,如下所示:``` % verbatim % % endverbatim % ```【参考方案3】:

我写了一个非常小的 django 应用程序:django-templatetag-handlebars 正是为了这个目的。

% load templatetag_handlebars %

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

使用Handlebars.js API 像往常一样渲染你的块:

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

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

我在@chrisv 发布它的包的那天写了它,并考虑了 KISS 方法。它主要基于 Miguel Araujo 的要点:https://gist.github.com/893408。

【讨论】:

【参考方案4】:

要在把手和 Django 之间进行更深入的集成(包括可选的动态预编译),请查看我的项目: https://bitbucket.org/chrisv/django-handlebars/

它基本上是这样工作的:

    下创建HB模板
    appdirectory/hbtemplates/myapp/template.html
    

    (就像 Django 模板一样)

    在您的应用中,使用

    % handlebars myapp % 
    

    模板标签和渲染模板如下:

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

【讨论】:

【参考方案5】:

先编译你的把手!

来自handlebars precompiling documentation:

除了减少下载大小之外,消除客户端编译将显着加快启动时间,因为编译是 Handlebars 最昂贵的部分。

您可以使用handlebars npm module 在构建环境中编译模板,或使用gulp-handlebars 将其与gulp 等构建工具集成。

编译后,您的车把模板可以用作静态资源并完全绕过服务器端渲染。也使缓存更容易:)

典型用法如下所示:

<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>

【讨论】:

【参考方案6】:

为什么不改用jinja2? IMO,它们使用起来都很优雅。这是一篇关于它的优秀文章:Using Jinja2 with Django

【讨论】:

我重新表述了我的问题,这不是更改 django 使用的模板系统的问题,我使用把手模板进行 dom 操作。【参考方案7】:

Django 的模板系统不支持一次转义块。如果不是因为在处理模板时,标记器不会保留关于标记在标记化之前的样子的确切信息,那么这将很容易解决。

我使用了以下变通方法,这很丑陋,但(有点)有效。在您的模板中使用不同的标签分隔符和一个 django 模板标签,将它们转换回您真正想要的:

@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 ), )

对于奖励积分,您可以在模板中利用 Django 的模板... 这可能会让你的大脑在以后试图解开:

% 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 %

【讨论】:

【参考方案8】:

实际上我编写了一个自定义模板过滤器,如下所示:

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

并在这样的模板中使用它:

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

这是我能想到的最简单的事情。您只需将您的车把变量名称放在引号中。我很遗憾在与 ssi 斗争之前我没有这个想法。它也适用于关键字:

"#each items"|handlebars

【讨论】:

以上是关于Django 模板中的 Handlebars.js的主要内容,如果未能解决你的问题,请参考以下文章

使用 handlebars.js 模板以数组中的最后一项为条件

markdown 在使用AJAX呈现的Handlebars.js模板文件上显示平面JSON文件中的数据。

Handlebars.js 模板引擎

Handlebars.js 是不是允许动态模板?

Handlebars.js模板

错误:Handlebars.js 中缺少帮助程序