Parts of this page are converted from the wheezy.template documentation. Thank you to the author. (akorn)
Fiole comes with a decent template engine. It supports the usual features of well known engines (Mako, Jinja2). The engine is derived from the wonderful wheezy.template package. It retains the same design goals:
In a nutshell, the syntax looks as simple as Bottle SimpleTemplate:
Simple template:
%require(user, items)
Welcome, {{user.name}}!
%if items:
%for i in items:
{{i.name}}: {{i.price}}.
%endfor
%else:
No item found.
%endif
This is a basic example for a route mapped to a template:
@get('/')
@get('/hello/<name>')
def hello(request, name=None):
return render_template(
source='Hello {{party.title() if party else "stranger"}}!', party=name)
In this case the template is not cached. It is built again for each request.
In order to activate the cache, the string template should be assigned to a name. The previous example becomes:
# Preload the cache
get_template('hello_tpl',
source="""Hello {{party.title() if party else "stranger"}}!""",
require=['party'])
@get('/')
@get('/hello/<name>')
def hello(request, name=None):
return render_template('hello_tpl', party=name)
Templates can be saved to files in the ./templates/ folder of the project. Then they are loaded by filename and cached in memory:
@get('/')
def index(request):
return render_template('hello.tmpl', party='World')
The variables which need to be extracted from the context are listed in the require directive. These names become visible to the end of the template scope (a template is like a Python function). The application passes variables to the template via context:
%require(var1, var2)
{{ var1 }} ... {{ var2 }}
For string templates, you can declare the variables using the require keyword argument:
>>> hello_tmpl = get_template(source='Hello {{ party.capitalize() }}!', require=['party'])
>>> hello_tmpl.render(party='WORLD')
u'Hello World!'
>>> hello_tmpl.render({'party': 'world'})
u'Hello World!'
This declaration is omitted when rendering the string directly:
>>> render_template(source='Hello {{party}}!', party='World')
u'Hello World!'
>>> #
>>> render_template(source='Hello {{ party.capitalize() }}!', party='world')
u'Hello World!'
Variable syntax is not limited to a single name access. You are able to use the full power of Python to access items in dictionary, attributes, function calls, etc...
Variables can be formatted by filters. Filters are separated from the variable by the | symbol. Filter syntax:
{{ variable_name|filter1|filter2 }}
The filters are applied from left to right so above syntax is equivalent to the following call:
{{ filter2(filter1(variable_name)) }}
The built-in filter |e converts any of & < > " ' to HTML-safe sequences & < > " '.
You can define and use custom filters. Here is an example how to switch to a different implementation for the html escape filter:
try:
from webext import escape_html
engine.global_vars['escape'] = escape_html
except ImportError:
pass
It tries to import an optimized version of html escape from the Webext package and assigns it to the escape global variable, which is aliased as e filter. The built-in escape is pure Python.
An example which demonstrates the standard |e filter:
>>> render_template('This: {{ data | e }}', data='"Hello small\' <i>World!<i>" ... & farther')
u'This: "Hello small' <i>World!<i>" ... & farther'
You can enable auto-escaping by default, then use |n as the last filter to bypass the default filters:
>>> engine.default_filters = ['e']
>>> render_template(source='Hello {{ party.capitalize() }}',
... party='<script src="evil" />')
u'Hello <script src="evil" />'
>>> render_template(source='Hello {{ party | n }}',
... party='<em>World</em>')
u'Hello <em>World</em>'
You are able to use engine Engine.global_vars dictionary in order to simplify your template access to some commonly used variables.
Any line starting with a single % contains either a template directive or Python code. Following directives are supported:
Template inheritance (%extends) allows to build a master template that contains common layout of your site and defines areas that child templates can override.
Master template is used to provide common layout of your site. Let define master template (filename shared/master.html):
<html>
<head>
<title>
%def title():
%enddef
{{title()}} - My Site</title>
</head>
<body>
<div id="content">
%def content():
%enddef
{{content()}}
</div>
<div id="footer">
%def footer():
© Copyright 2014 by Him.
%enddef
{{footer()}}
</div>
</body>
</html>
In this example, the %def tags define python functions (substitution areas). These functions are inserted into specific places (right after definition). These places become placeholders for child templates. The %footer placeholder defines default content while %title and %content are just empty.
Child templates are used to extend master templates via placeholders defined:
%extends("shared/master.html")
%def title():
Welcome
%enddef
%def content():
<h1>Home</h1>
<p>
Welcome to My Site!
</p>
%enddef
In this example, the %title and %content placeholders are overriden by the child template.
The include is useful to insert a template content just in place of call:
%include("shared/snippet/script.html")
The import is used to reuse some code stored in other files. So you are able to import all functions defined by that template:
%import "shared/forms.html" as forms
{{ forms.textbox('username') }}
or just a certain name:
%from "shared/forms.html" import textbox
{{ textbox(name='username') }}
Once imported you use these names as variables in the template.
Any line starting with a single % and which is not recognized as a directive is actual Python code. Its content is copied to the generated source code.
The %import and %from lines can be either directives or Python commands, depending on their arguments.
In addition to the special %def, all kinds of Python blocks are supported. The indentation is not significant, blocks must be ended explicitly.
The empty %return directive triggers an early return in the template. The code execution is stopped and the generated content is returned.
Here is a simple example:
%require(items)
%if items:
%for i in items:
{{i.name}}: {{i.price}}.
%endfor
%else:
No items found.
%endif
Only single line comments are supported.
The %# directive introduces a one-line comment. Comments are removed before the template is compiled.
%# TODO:
The line after the %def directive must not enter a new block (%for, %if, etc...). A workaround is to insert an empty comment line before opening the block.
The variables used in the template should be declared, either with a %require directive (recommended for templates loaded from the filesystem), or passed as keyword argument (require=["nav", "body"]) when preparing the template (recommended for string templates). When using the render_template() function with a (source="...") keyword argument, the declaration %require is automatically generated based on the names of the other keyword arguments passed to the function.
These features are not supported (among others):