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 &lt;b&gt;World&lt;/b&gt;!'
>>> 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 程序。

在 0.12 版本中修改: 在此版本之前,include()rebase() 是语法关键字,而不是函数。

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

SimpleTemplate API

class SimpleTemplate[source]
prepare(escape_func=<function html_escape>, noescape=False, syntax=None, **ka)[source]

运行准备工作(解析、缓存等)。应该可以再次调用此方法来刷新模板或更新设置。

render(*args, **kwargs)[source]

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