Handlebars.js в шаблонах Django

Мне нужна система шаблонов 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 %}}

редактировать

Скорее всего, я нашел это. Работает нормально.

Обновить

Django 1.5 изначально поддерживает буквенный тег.

8 ответов

Решение

Есть ли в шаблонах django тег, чтобы остановить рендеринг блока с помощью фигурных скобок?

СТАРЫЙ Ответ для Django 1.0-1.4: Нет, хотя вы могли бы поместить блок в отдельный файл и включить его без рендеринга или использовать другой движок шаблонов.

Новый ответ: Ответ выше был правильным в августе 2011 года, когда на вопрос был задан и дан ответ. Начиная с версии Django 1.5 (выпущенной в феврале 2013 года, хотя альфа / бета-версии были в конце 2012 года), они представили {% 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 %}

Документация по стенограмме здесь. Да, это было отмечено другими ранее, но так как это принятый ответ, я должен перечислить самое простое решение.

Я использую пользовательский тег шаблона для другой системы шаблонов js, здесь: https://gist.github.com/629508

Использовать в шаблоне:

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

Редактировать: этот пользовательский тег шаблона больше не нужен, так как язык шаблонов Django теперь поддерживает тег шаблона {% verbatim %}.

Я написал очень маленькое приложение django: http://pypi.python.org/pypi/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. В основном он основан на сути Мигеля Араужо: https://gist.github.com/893408.

Для более глубокой интеграции между рулем и Django (включая дополнительную предварительную компиляцию на лету) проверьте мой проект по адресу https://bitbucket.org/chrisv/django-handlebars/

Это в основном работает так:

  1. создать шаблон HB под

    appdirectory/hbtemplates/myapp/template.html
    

    (так же, как шаблон Django)

  2. в вашем приложении используйте

    {% handlebars myapp %} 
    

    Шаблон тега и визуализировать шаблон так:

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

Сначала скомпилируйте руль!

Из руля предварительной компиляции документации:

В дополнение к уменьшению размера загрузки, устранение компиляции на стороне клиента значительно ускорит время загрузки, поскольку компиляция является самой дорогой частью Handlebars.

Вы можете скомпилировать шаблоны в вашей среде сборки, используя модуль nleb handlebars, или интегрировать его с инструментом сборки, таким как gulp с gulp-handlebars.

После компиляции ваши шаблоны руля могут использоваться как статические ресурсы и вообще обходить рендеринг на стороне сервера. Облегчает кеширование тоже:)

Типичное использование будет выглядеть так:

<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 не поддерживает экранирование блоков одновременно. Было бы легко обойти эту проблему, если бы не факт, что при обработке шаблонов токенизатор не хранит точную информацию о том, как выглядели токены до того, как они были токенизированы.

Я использовал следующий обходной путь, который уродлив, но (вроде) работает. Используйте разные разделители тегов в своих шаблонах и тег шаблона 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 %}

Почему бы не использовать jinja2 вместо этого? ИМО, они оба элегантны в использовании. Вот отличная статья об этом: Использование Jinja2 с Django

На самом деле я написал собственный шаблонный фильтр, который выглядит так:

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}}
Другие вопросы по тегам