SimpleTemplate¶
Bottle 内置了一个快速、强大且易于学习的模板引擎,名为 SimpleTemplate 或简称为 stpl。它是 view()
和 template()
助手函数使用的默认引擎,也可作为一个独立的通用模板引擎使用。本文档解释了模板语法并展示了常见用例的示例。
基本 API 用法
SimpleTemplate
实现了 BaseTemplate
API
>>> 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 语言特性、库和速度的完全访问权限。
警告
SimpleTemplate
语法直接编译成 Python 字节码,并在每次调用 SimpleTemplate.render()
时执行。不要渲染不受信任的模板!它们可能包含并执行有害的 Python 代码。
内联表达式¶
你已经从上面的“Hello World!”示例中了解了 {{...}}
语法的用法,但还有更多内容:只要能评估为字符串或具有字符串表示形式的内容,任何 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 <b>World</b>!'
>>> template('Hello {{!name}}!', name='<b>World</b>')
u'Hello <b>World</b>!'
嵌入式 Python 代码¶
模板引擎允许你在模板中嵌入 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.
空白字符控制¶
代码块和代码行总是跨越整行。代码段之前和之后的空白字符会被去除。由于嵌入式代码,你的模板中不会出现空行或悬空空白字符
<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 程序。
- include(sub_template, **variables)¶
使用指定的变量渲染子模板,并将结果文本插入到当前模板中。该函数返回一个字典,其中包含传递给子模板或在子模板中定义的局部变量
% include('header.tpl', title='Page Title') Page Content % include('footer.tpl')
- rebase(name, **variables)¶
标记当前模板,使其稍后包含在另一个模板中。当前模板渲染完成后,其结果文本存储在一个名为
base
的变量中,并传递给基础模板(base-template),然后渲染基础模板。这可以用来用周围的文本包装一个模板,或者模拟其他模板引擎中的继承特性% 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