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/
Это в основном работает так:
создать шаблон HB под
appdirectory/hbtemplates/myapp/template.html
(так же, как шаблон Django)
в вашем приложении используйте
{% 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}}