Thus far we have spent a lot of time covering CherryPy. I think it is high time to cover our choice of view template engine, Mako. As a reminder, view system components serve to present data that is being fed to it from the controllers. Ideally view templates should be given all of the data they need to render appropriately, and not have to request more information from the data models directly. The view template then cherry picks (no pun intended) from the data it is given and formats it into an appropriate view of the data given the task at hand, for instance an summary of a posts versus the full entries.
Mako is a template library written in Python. HTML markup is intermixed with Python varaibles, control structures and statements. As such it uses similar approaches to JSP, ASP and PHP, but given the origins in MVC style Web applications, it is closer to ERB templates in Ruby land. Strictly speaking, Mako can produce any text format, not just HTML, but that is it’s main purpose.
Sidebar: Mako templates are compiled to Python modules at runtime for maximum performance. This has implications on memory and CPU usage quotas for GAE, but only if you have a tremendous amount of templates. In any case, you can configure Mako to only hold a certain amount of pre-compiled templates in memory, and the engine will retire the oldest (base on last access time) templates to make room for the new.
Let’s take a look at a basic example:
<%!
import re
def censor(text):
return re.sub(r'ass', 'butt', text)
%>
<%
msg = "<b>Hello World!</b>"
%>
<html>
<body>
<p>Hello World!</p>
<p>${ msg }</p>
<p>${ msg | h }</p>
<p>
"Classic mistake" == ${ censor("Classic mistake") }
</p>
</body>
</html>
OK, that’s a lot to take in, so let’s review each piece in turn. First and foremost are the directives for arbitrary Python blocks, denoted by <% … %> and module level blocks, denoted by <%! … %>. The difference between the two is that module level blocks are only evaluated on loading the template on the first time into memory, which may only be once per application. Ideally these module level blocks should be used for imports and some method definitions. The blocks follow all of the syntax rules for Python, including proper indentation.
Next is a simple expression substitution, denoted by ${ … }. The contents within the ${} tag are evaluated by Python directly and evaluated directly into a string before handing the result back to the template. You can also call any imported function or functions defined within the scope of the template, such as the censor() function defined in the module block.
If the content for the expression is user-supplied (e.g. user generated content from the data store or forms) you often want to further process that result before presenting it to the client for security reasons (e.g. preventing malicious Javascript). This is done by using filters to escape the expression’s output string to something that is non-threatening to a browser. These escapes can be added to an expression substituion using the | operator:
${ "<script> alert(\"danger will robinson\") ; </script> " | h }
The above expression produces
<script> alert("danger will robinson"); </script>
instead of the possibly malicious javascript within the content of the expression. Mako includes a number of built-in escaping mechanisms, including HTML, URI and XML escaping, as well as a “trim” function.
Control Structures
Mako templates provides the basic set of control structures – conditionals (i.e. if/elif/else), loops ( while and for), and exception handling ( try/except). These are denoted by a plain “%” sign as the first non-whitespace character on a line. Since Python indentation does not apply to them, must be explicitly ended by the corresponding end tag. Here are two examples copied from the Mako docs:
% if x==5:
this is some output
% endif
% for a in ['one', 'two', 'three', 'four', 'five']:
% if a[0] == 't':
its two or three
% elif a[0] == 'f':
four/five
% else:
one
%endif
% endfor
As you can see, the conditions and iterators from Python work just fine.
Tags
In addition to these Python-embedding structures, Mako provide a few XML tags for adding functionality specific to the Mako templates. The tag names all begin with “%” but are not like the Python block demarkations since the tag end does not have a corresponding “%”. Confusing, I know, but here is the basic syntax format:
<%include file="foo.txt"/>
<%def name="foo" buffered="True">
this is a def
</%def>
Notice how the closing “>” is not prefixed with “%” as the Python blocks are. Also notice that when the tag has content, the closing tag follows XML syntax. The following table lists the available tags and attributes:
| Tag |
Description |
| %page |
defines general characteristics of the template |
| %include |
include another template, optionally passing arguments to it |
| %def |
defines a Python function which contains a set of content and can be called at some other point in the template |
| %namespace |
Like Python import statement, allows access to rendering functions and metadata of other template files, Python modules, etc. |
| %inherit |
allows templates to arrange themselves in inheritance chains |
| %call |
used to call <%defs> with additional embedded content |
| %doc |
multiline comments |
| %text |
suspends parsing and returns the content as plain text |
All of the tags are very well documented in the Mako documentation, but it is worth discussing at the tag, which defines functions like the Python def, but the content of the tag follows the syntax rules of Mako. These are compiled into Python bytecode and can be evaluated in expression statements like so:
<%def name="int_square(x)">
Integer square of ${x} is ${ int(x) * int(x) }
</%def>
${ int_square(33) }
Next post, we’ll cover how templates can call and include each other using the inherit tag.
Tags: App Engine, AppEngine, GAE, MainStory, Mako
Recent Comments