python template
模板引擎
所谓模板,特别是web模板,是一种表示数据的方式,这种方式旨在提高可读性。模板通常看起来是最终的输出,其中使用占位符代替实际数据(或简化形式的示例数据),带有通用的样式和视觉元素。使用模板呈现的数据可以分为两个部分:template模板本身所需要的数据(如web页面中固定的部分如导航栏、按钮等)、需要呈现(render)的数据data
Python的模板引擎很多,如django template system、Jinja 2、Mako、Cheetah3、mustache等。更多可参看Templating in Python
这里先介绍下python string模块提供的Template类template strings和mustache,其他可关注后续文章
template strings
- 官方文档
- 模板规则:
$$
为转义符号,它会被替换为单个的$
$identifier
为替换占位符,它会匹配一个名为 "identifier" 的映射键。 在默认情况下,"identifier" 限制为任意 ASCII 字母数字(包括下划线)组成的字符串,不区分大小写,以下划线或 ASCII 字母开头。 在$
字符之后的第一个非标识符字符将表明占位符的终结${identifier}
等价于$identifier
。 当占位符之后紧跟着有效的但又不是占位符一部分的标识符字符时需要使用,例如${noun}ification
- substitute:执行模板替换,返回一个新字符串
- safe_substitute:类似于 substitute(),不同之处是如果有占位符未在 mapping 和 kwds 中找到,不是引发 KeyError 异常,而是将原始占位符不加修改地显示在结果字符串中,且任何在其他情况下出现的
$
将简单地返回$
而不是引发 ValueError - 使用示例
from string import Template
s = Template('$who likes $what')
print(s.substitute(who='jerry', what='tom'))
d = dict(who='lilei')
# print(s.substitute(d)) # KeyError: 'what'
print(s.safe_substitute(d))
# s = Template('Give $who $100') # ValueError: Invalid placeholder in string: line 1, col 11
s = Template('Give $who $$100')
print(s.substitute(d))
s = Template('${who} likes ${language}books')
print(s.safe_substitute({"who": "jerry", "language": "python"}))
-----------------输出结果------------
jerry likes tom
lilei likes $what
Give lilei $100
jerry likes pythonbooks
简单应用
使用模板template.html生成报告report.html
- template.html,其中包含模板占位符
${elements}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Great Books of All Time</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>Great Books of All Time</h1>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Author</th>
<th scope="col">Book Title</th>
</tr>
</thead>
<tbody>
${elements}
</tbody>
</table>
</div>
</body>
</html>
- 作者和书名对应关系data.json
{
"Dale Carnegie": "How To Win Friends And Influence People",
"Daniel Kahneman": "Thinking, Fast and Slow",
"Leo Tolstoy": "Anna Karenina",
"William Shakespeare": "Hamlet",
"Franz Kafka": "The Trial"
}
- 生成report.html
import json
import string
with open("data.json") as f:
data = json.loads(f.read())
print(data)
content = ""
for i, (author, title) in enumerate(data.items()):
content += "<tr>"
content += f"<td>{i + 1}</td>"
content += f"<td>{author}</td>"
content += f"<td>{title}</td>"
content += "</tr>"
print(content)
with open("template.html") as t:
template = string.Template(t.read())
final_output = template.substitute(elements=content)
with open("report.html", "w") as output:
output.write(final_output)
mustache
logic-less templates based on CTemplate ,mustache有很多语言的实现,其中python版本的实现是chevron
安装
pip install chevron
使用示例
- 命令行
usage: chevron [-h] [-v] [-d DATA] [-p PARTIALS_PATH] [-e PARTIALS_EXT]
[-l DEF_LDEL] [-r DEF_RDEL]
template
positional arguments:
template The mustache file
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-d DATA, --data DATA The json data file
-p PARTIALS_PATH, --path PARTIALS_PATH
The directory where your partials reside
-e PARTIALS_EXT, --ext PARTIALS_EXT
The extension for your mustache partials, 'mustache'
by default
-l DEF_LDEL, --left-delimiter DEF_LDEL
The default left delimiter, "{{" by default.
-r DEF_RDEL, --right-delimiter DEF_RDEL
The default right delimiter, "}}" by default.
- render
def render(template='', data={}, partials_path='.', partials_ext='mustache',
partials_dict={}, padding='', def_ldel='{{', def_rdel='}}',
scopes=None, warn=False):
"""Render a mustache template.
Renders a mustache template with a data scope and partial capability.
Given the file structure...
╷
├─╼ main.py
├─╼ main.ms
└─┮ partials
└── part.ms
then main.py would make the following call:
render(open('main.ms', 'r'), {...}, 'partials', 'ms')
Arguments:
template -- A file-like object or a string containing the template
data -- A python dictionary with your data scope
partials_path -- The path to where your partials are stored
If set to None, then partials won't be loaded from the file system
(defaults to '.')
partials_ext -- The extension that you want the parser to look for
(defaults to 'mustache')
partials_dict -- A python dictionary which will be search for partials
before the filesystem is. {'include': 'foo'} is the same
as a file called include.mustache
(defaults to {})
padding -- This is for padding partials, and shouldn't be used
(but can be if you really want to)
def_ldel -- The default left delimiter
("{{" by default, as in spec compliant mustache)
def_rdel -- The default right delimiter
("}}" by default, as in spec compliant mustache)
scopes -- The list of scopes that get_key will look through
warn -- Issue a warning to stderr when a template substitution isn't found in the data
Returns:
A string containing the rendered template.
"""
...
...
- 使用示例
import chevron
template = 'Hello, {{ mustache }}!'
data = {'mustache': 'World'}
s = chevron.render(template, data)
print(s)
with open('template.html', 'r') as f:
s = chevron.render(f, {'mustache': 'World'})
print(s)
args = {
'template': 'Hello, {{ mustache }}!',
'data': {
'mustache': 'World'
}
}
s = chevron.render(**args)
print(s)
args = {
'template': 'Hello, {{> thing }}!',
'partials_dict': {
'thing': 'World'
}
}
s = chevron.render(**args)
print(s)
这里用的模板规则都是
{{}}
,更多规则可参考mustache manual
简单应用
还是上面生成报告,同样可以使用 mustache 来实现
- 将template.html的模板规则改成
{{{ elements }}}
- 修改程序如下
import chevron
import json
with open('data.json', 'r') as f:
data = json.loads(f.read())
content = ""
for i, (author, title) in enumerate(data.items()):
content += "<tr>"
content += f"<td>{i + 1}</td>"
content += f"<td>{author}</td>"
content += f"<td>{title}</td>"
content += "</tr>"
output = chevron.render(open('template.html', 'r'), {'elements': content})
with open('report.html', 'w') as f:
f.write(output)