SimpleTemplate 模板引擎

Bottle自带了一个快速,强大,易用的模板引擎,名为 SimpleTemplate 或简称为 stpl 。它是 view()template() 两个函数默认调用的模板引擎。接下来会介绍该引擎的模板语法和一些常见用例。

基础API :

SimpleTemplate 类实现了 BaseTemplate 接口

>>> from bottle import SimpleTemplate
>>> tpl = SimpleTemplate('Hello {{name}}!')
>>> tpl.render(name='World')
u'Hello World!'

简单起见,我们在例子中使用 template() 函数

>>> from bottle import template
>>> template('Hello {{name}}!', name='World')
u'Hello World!'

还可以使用关键字参数将字典传递到模板中::

>>> from bottle import template
>>> my_dict={'number': '123', 'street': 'Fake St.', 'city': 'Fakeville'}
>>> template('I live at {{number}} {{street}}, {{city}}', **my_dict)
u'I live at 123 Fake St., Fakeville'

注意,编译模板和渲染模板是两件事情,尽管 template() 函数隐藏了这一事实。通常,模板只会被编译一次,然后会被缓存起来,但是会根据不同的参数,被多次渲染。

SimpleTemplate 的语法

虽然Python是一门强大的语言,但它对空白敏感的语法令其很难作为一个模板语言。SimpleTemplate移除了一些限制,允许你写出干净的,有可读性的,可维护的模板,且保留了Python的强大功能。

警告

The SimpleTemplate syntax compiles directly to python bytecode and is executed on each SimpleTemplate.render() call. Do not render untrusted templates! They may contain and execute harmful python code.

内嵌表达式

你已经学会了 {{{{...}}}} “你好,世界”的句法。上面的示例,但还有更多:只要计算为字符串或具有字符串表示形式的内容,就允许在大括号中使用任何python表达式:

>>> template('Hello {{name}}!', name='World')
u'Hello World!'
>>> template('Hello {{name.title() if name else "stranger"}}!', name=None)
u'Hello stranger!'
>>> template('Hello {{name.title() if name else "stranger"}}!', name='mArC')
u'Hello Marc!'

{{}}中的Python语句会在渲染的时候被执行,可访问传递给 SimpleTemplate.render() 方法的所有参数。默认情况下,自动转义HTML标签以防止 XSS 攻击。可在语句前加上"!"来关闭自动转义。

>>> template('Hello {{name}}!', name='<b>World</b>')
u'Hello &lt;b&gt;World&lt;/b&gt;!'
>>> template('Hello {{!name}}!', name='<b>World</b>')
u'Hello <b>World</b>!'

嵌入Pyhton代码

模板引擎允许您在模板中嵌入python代码的行或块。代码行以开头 % 代码块被 <%%> 令牌:

% name = "Bob"  # a line of python code
<p>Some plain text in between</p>
<%
  # A block of python code
  name = name.title().strip()
%>
<p>More plain text</p>

嵌入的python代码遵循常规的python语法,但有两个附加的语法规则:

  • 缩进被忽略。 您可以在语句前面放尽可能多的空白。这允许您将代码与周围的标记对齐,并可以大大提高可读性。

  • 通常缩进的块现在必须用 end 关键字。

<ul>
  % for item in basket:
    <li>{{item}}</li>
  % end
</ul>

两个 % 以及 <% 只有当令牌是一行中的第一个非空白字符时,才能识别它们。如果它们出现在模板标记的中间文本中,则不必转义它们。只有当一行文本以这些标记中的一个开头时,才必须用反斜杠将其转义。在极少数情况下,反斜杠+标记组合出现在标记的行首,您可以随时帮助自己在内联表达式中使用字符串:

This line contains % and <% but no python code.
\% This text-line starts with the '%' token.
\<% Another line that starts with a token but is rendered as text.
{{'\\%'}} this line starts with an escaped token.

如果你发现自己需要逃避很多,考虑使用 custom tokens .

注意 %<% %> 工作 确切地 同样的方法。后者只是一种方便的方法,可以减少输入并避免较长代码段的混乱。这意味着 <% %> 块中,所有缩进的代码都必须以 end ,如下例所示:

<%
    if some_condition:
        some_operation()
    elif some_other_condition:
        some_other_operation()
    else:
        yet_another_operation()
        if yet_another_condition:
          some_more_stuff()
        end
    end
%>

空白控件

代码块和代码行总是横跨整行。去掉代码段后前面的空白。由于嵌入的代码,您不会在模板中看到空行或悬空:

<div>
 % if True:
  <span>content</span>
 % end
</div>

此代码段呈现为干净和紧凑的HTML::

<div>
  <span>content</span>
</div>

但是嵌入代码仍然需要您开始一个新行,这可能不是您希望在呈现的模板中看到的内容。要跳过代码段前面的换行符,请以双反斜杠结束文本行::

<div>\\
 %if True:
<span>content</span>\\
 %end
</div>

这次呈现的模板如下所示:

<div><span>content</span></div>

这只能直接在代码段前面工作。在所有其他地方,您可以自己控制空白,不需要任何特殊的语法。

模板函数

每个模板都预加载了一组函数,这些函数有助于处理最常见的用例。这些功能始终可用。你不必自己进口或提供。对于这里没有介绍的所有内容,可能都有好的python库可用。记住你可以 import 模板中的任何内容。毕竟它们是python程序。

在 0.12 版更改: 在此发布之前, include()rebase() 是语法关键字,不是函数。

include(sub_template, **variables)

使用指定的变量呈现子模板,并将结果文本插入当前模板。函数返回一个字典,其中包含传递给子模板或在子模板中定义的局部变量:

% include('header.tpl', title='Page Title')
Page Content
% include('footer.tpl')
rebase(name, **variables)

将当前模板标记为以后包含在其他模板中。当前模板呈现后,其结果文本存储在名为 base 并传递到基本模板,然后呈现该模板。这个可以用来 wrap 包含周围文本的模板,或模拟在其他模板引擎中找到的继承功能:

% rebase('base.tpl', title='Page Title')
<p>Page Content ...</p>

这可以与以下内容结合使用 base.tpl ::

<html>
<head>
  <title>{{title or 'No title'}}</title>
</head>
<body>
  {{!base}}
</body>
</html>

访问模板中未定义的变量会引发 NameError 并立即停止渲染。这是标准的python行为,并不新鲜,但是普通的python缺乏检查变量可用性的简单方法。如果您想要支持灵活的输入,或者在不同的情况下使用相同的模板,这很快就会变得烦人。这些功能可能有助于:

defined(name)

如果变量已定义则返回True,反之返回False。

get(name, default=None)

返回该变量,或一个默认值

setdefault(name, default)

如果该变量未定义,则定义它,赋一个默认值,返回该变量

下面是使用了这三个函数的例子,实现了模板中的可选参数。

% setdefault('text', 'No Text')
<h1>{{get('title', 'No Title')}}</h1>
<p> {{ text }} </p>
% if defined('author'):
  <p>By {{ author }}</p>
% end

SimpleTemplate API

class SimpleTemplate(source=None, name=None, lookup=None, encoding='utf8', **settings)[源代码]
prepare(escape_func=<function html_escape>, noescape=False, syntax=None, **ka)[源代码]

运行准备(分析、缓存…)。应该可以再次调用它来刷新模板或更新设置。

render(*args, **kwargs)[源代码]

使用关键字参数作为局部变量呈现模板。