Chapter 5: Using View Templates +++++++++++++++++++++++++++++++ .. index :: single: Chap 5-Using View Templates Real web applications require the generation of a lot of HTML pages. In the ``HelloWorld`` example from Chapter 3, you saw how to generate a string in Python code and return it from a controller action to the user’s browser to produce some visible output. .. index :: single: description of; templating system If you tried to generate a whole web application with lots of different HTML pages by generating strings in Python code, it would quickly become rather cumbersome because the Python language was not specifically designed to make it easy to generate HTML. Instead, it is often helpful to use a *templating system*. Rather than writing Python code containing HTML strings, templating systems typically allow you to write HTML directly and embed Python code in your HTML when you need to do so. Since most of your template is likely to be HTML rather than Python, this is often a lot quicker. Templating languages typically also offer simple constructs for substituting variables or repeating certain sections of HTML. .. index :: single: example of; Mako templating language Introducing Mako ================ Here is a simple template written using Pylons’ default templating language, Mako. It simply prints a personalized greeting: ::
Hello ${name}!
.. index :: single: ${} construct, for templates As you can see, most of the template consists of HTML. Areas of the template that represent Python expressions that add to the content of the template are written inside ``${}``. In this example, the value of ``name`` would replace the ``${name}`` text when the template was rendered. Let’s see how to use this template in Pylons. Throughout this chapter, you’ll create a new Pylons application that demonstrates various features of Mako, and by the end of the chapter, you will have created a complete set of templates you can use in your own Pylons application. Start by creating a new project. Once again, you will be asked some questions; you can choose the defaults: :: $ paster create --template=pylons TemplateDemo Selected and implied templates: Pylons#pylons Pylons application template Variables: egg: TemplateDemo package: templatedemo project: TemplateDemo Enter template_engine (mako/genshi/jinja/etc: Template language) ['mako']: Enter sqlalchemy (True/False: Include SQLAlchemy 0.4 configuration) [False]: Enter google_app_engine (True/False: Setup default appropriate for Google App Engine) [False]: Creating template pylons Creating directory ./TemplateDemo Recursing into +package+ Creating ./TemplateDemo/templatedemo/ Copying __init__.py_tmpl to ./TemplateDemo/templatedemo/__init__.py Recursing into config ... etc .. index :: single: templating system Remember that the ``--template`` option in the previous command refers to *project* templates used to create a project directory structure for you, whereas this chapter is about *view* templates used to help render the HTML for a view. .. index :: single: storing; view template single: editing; config/environment.py file Pylons projects store view templates in the project’s ``templates`` directory, but if you want to store them somewhere else, you can configure where Pylons should tell Mako to look to find your view templates by editing your project’s ``config/environment.py`` file. By default, it looks like this: :: # Create the Mako TemplateLookup, with the default autoescaping config['pylons.app_globals'].mako_lookup = TemplateLookup( directories=paths['templates'], ... ) You can replace ``paths['templates']`` with a list of the places that Mako should search for view templates. Mako searches the directories in order. .. index :: single: testing; view template single: greeting.html template sample Now that the project has been created, let’s test the greeting example you saw earlier. Save the greeting template in the ``TemplateDemo/templatedemo/templates/`` directory as ``greeting.html``. You’ll also need a controller to test the template. Create a new controller in your ``TemplateDemo`` project named ``greeting``: :: $ cd TemplateDemo $ paster controller greeting Update the ``index()`` action of the ``greeting`` controller so that it looks like this: :: def index(self): name = 'Pylons Developer' return render('/greeting.html', extra_vars={'name': name}) The ``render()`` function is imported at the top of the controller from your project’s ``lib/base.py`` file. Within that file you’ll find the import below so the ``render()`` function in your controller is really just an alias for Pylons’ ``render_mako()`` function: :: from pylons.templating import render_mako as render .. index :: single: ?FS? (forward slash), template paths and You’ll look at how to use other templating languages later in the chapter. Also notice that the template paths have to start with a slash (``/``). This requirement was introduced in Pylons 0.9.6. .. index :: single: testing; view template If you start the server with the ``paster serve --reload development.ini`` command and visit http://localhost:5000/greeting/index, you should see the ``Hello Pylons Developer!`` greeting in your browser (see Figure 5-1). .. figure :: 9349f0501.png :target: _images/9349f0501.png :scale: 70 :alt: Figure 5-1. The output produced by the ``greeting.html`` template Figure 5-1. The output produced by the ``greeting.html`` template Using the Template Context c Global ----------------------------------- .. index :: single: assigning variables using context c global; view template Although passing the ``name`` argument directly as an extra argument to ``render()`` works perfectly well, it is usually considered a better practice to assign template variables to Pylons via the template context global ``c``, which you learned about in Chapter 3. Here is the updated controller: :: def index(self): c.name = 'Pylons Developer' return render('/greeting.html') Before you can use the ``c`` global, it needs importing into your controller: :: from pylons import tmpl_context as c .. index :: single: assigning template variables to c compared to passing them directly as arguments to; render() function You might prefer to assign template variables to ``c`` rather than pass them in directly as arguments to ``render()`` for two reasons: * There is less chance you will accidentally assign a variable that has the same name as either one of the Pylons globals or one of the global names set up by Mako. * If a particular variable is useful in a template, there is a good chance it will be useful elsewhere in your application too. Since the ``c`` object is a Pylons global, you can also use objects assigned as attributes of ``c`` elsewhere in your application during a request. Here’s the updated ``greeting.html`` template: ::Hello ${c.name}!
Notice that this time the call to ``render()`` doesn’t include the ``c`` global explicitly. Pylons automatically passes this and other globals to Mako anyway, so you don’t need to do so yourself. If you test this updated example, you will see the same output as before. .. caution :: .. index :: single: underscore (_) character and global variables Be careful when setting ``c`` attributes that begin with an underscore (``_``) character. ``c`` and other global variables are really a ``StackedObjectProxy``, which reserve the attribute names ``_current_obj``, ``_push_object``, and ``_pop_object`` for their internal methods. You’ll learn about how these objects actually work under the hood in Chapter 17. .. index :: single: assigning variables using context c global; view template The ``c`` global is reset on each request so that you don’t need to worry about a controller still having old values set from a previous request. One issue you learned about in Chapter 3 is that the ``c`` object doesn’t raise an ``AttributeError`` when you attempt to access an attribute that doesn’t exist and instead returns an empty string. This behavior is confusing for new Pylons developers (as well as more experienced ones), so it is recommended you disable it by specifying the ``strict_c`` option in ``config/environment.py``. Add a new line after the Pylons configuration options: :: # CONFIGURATION OPTIONS HERE (note: all config options will override # any Pylons config options) config['pylons.strict_c'] = True The template context global ``c`` makes it easy to pass information around your application, but it is available only during a request. As a result, you should be very careful about creating libraries that explicitly rely on it; otherwise, your code might quickly become quite tangled. As an example, imagine you had assigned the variables ``name`` and ``age`` to the ``c`` object and then created a function that performed some simple formatting. You might be tempted to write it like this: :: from pylons import c def format_age(): return "Name: %s, Age: %s"%(c.name, c.age) .. index :: single: assigning variables using context c global; view template Although this works perfectly well, it is bad practice—your function can be used only when Pylons is processing an HTTP request because this is the only time the ``c`` global is available. It is much better to write your function like this: :: def format_age(name, age): return "Name: %s, Age: %s"%(name, age) and then to use it like ``format_age(c.name, c.age)`` so that the function itself does not rely on the presence of the ``c`` global. This will make it much more obvious how your code works and will make refactoring later much easier. .. index :: single: assigning variables using context c global; view template For the same reason, it is better to avoid using other Pylons globals such as ``request`` and ``response`` where possible. Being explicit is usually a good idea. Basic Template Syntax --------------------- .. index :: single: basic syntax; view template Now that you’ve seen how a very simple template works, it is time to look in more detail at the template syntax you’ll frequently use when working with Mako templates. If you’d like to follow along with any of the examples in this section, create a new template called ``basic.html``, and then create a new action in the controller to render it, because you will return to the ``greeting.html`` example later in the chapter so shouldn’t change that template now. :: def basic(self): return render('/basic.html') .. index :: single: ${} construct, for templates Let’s get started. You’ve already seen basic expression substitution using the ``${}`` construct. You can use any valid Python expression that would be suitable as a function argument within the brackets. Here is an example: :: The value of 3 + 5 is: ${3 + 5} A string representation of 3 to the power 4 is ${pow(3, 4)} .. index :: single: adding to templates; comments You can add comments to your templates by starting a line with the ``##`` characters. A single ``#`` is used quite a lot in templates for CSS selectors and output for various programming languages, so it was decided ``##`` should be used for comments rather than adopting the Python comment format of a single ``#`` character. Make sure the ``##`` characters are at the very start of the line with no whitespace. For example: :: ## This is a comment which will not be rendered This will be rendered ## and so will this. .. index :: single: %(%doc%) tag You can also use multiline comments using ``<%doc>`` tags. For example: :: <%doc> This is a multiline comment which will not be rendered. This style of comment is particularly useful for documentation as well as situations where you want to comment out a large region of your template temporarily during testing. %doc> .. index :: single: basic syntax; view template Related to the ``<%doc>`` tag is the ``<%text>`` tag, which simply outputs verbatim whatever text is specified without treating it as Mako markup. This is very handy for documenting Mako. For example, the following: :: <%text> This is some Mako syntax which will not be executed: ${variable} Neither will this <%doc>be treated as a comment%doc> %text> produces the unchanged output, as you would expect: :: This is some Mako syntax which will not be executed: ${variable} Neither will this <%doc>be treated as a comment%doc> You might need to view the HTML source code to see that this is indeed the output produced because some web browsers, including Internet Explorer, don’t handle tags containing ``%`` characters such as the ``<%doc>`` and ``%doc>`` tags in this example. .. index :: single: in Mako; control structures Mako also supports the full range of control structures supported by Python, including ``if``, ``elif``, ``else``, ``while``, and ``for``. These structures are very useful in templates. For example, to control which information is displayed, you might use an ``if`` statement: :: % if c.name == 'Pylons Developer': Welcome Pylons Developer % else: Welcome guest % endif These statements work in the same way they would in Python, including the need for a colon (``:``) at the end of the line. The only difference is that because templates don’t have to conform to the strict indentation rules that Python source code follows, you have to specify the point at which the control structure ends. In this case, you used an ``% endif`` line, but if you were using a ``while`` loop, for example, you would use ``% endwhile``. You can, of course, combine control structures too. For example, you might want to generate an HTML list from a data structure that looks like this: :: c.links = [ ('James','http://jimmyg.org'), ('Ben','http://groovie.org'), ('Philip',''), ] .. index :: single: basic syntax; view template The template might look like this: ::Hello ${c.name}! You are visiting ${h.url_for()}
.. index :: single: objects passed automatically via; render() function Later in the chapter when you look at custom ``render()`` functions, you will see how you can customize which variables are used by default. For more information about template variables, see http://docs.pylonshq.com/views/#default-template-variables. Mako Runtime Built-Ins ---------------------- .. index :: single: runtime built-ins; Mako templating language single: Mako documentation; web sites In addition to the Pylons default template variables that the Pylons ``render()`` global sets up for you, it is worth being aware that Mako sets up a number of runtime built-ins for you. I’ll mention most of these in the course of this chapter, but for full information about each, you should consult the Mako documentation at http://www.makotemplates.org/docs/documentation.html#runtime_builtins. Here’s a quick summary so that you can make sure you don’t accidentally use any of these as names of your own variables in templates: .. index :: single: description of; context object (Mako) ``context`` This context is the central object that is created when a template is first executed and is responsible for handling all communication with the outside world. It includes the output buffer and a dictionary of the variables that can be freely referenced within a template; this includes the other Mako runtime built-ins, the Pylons default variables, and any extra variables passed by the ``extra_variables`` argument to ``render()``. As such, the ``context`` object is very important. You can learn more about it at http://www.makotemplates.org/docs/documentation.html#runtime. .. index :: single: Mako; namespaces ``local``, ``self``, ``parent``, and ``next`` These are all namespaces and have particular meanings in the context of template inheritance chains. You’ll look at these later in the chapter. .. index :: single: capture() function (Mako) single: def (Mako) ``capture`` This is a function that calls a given def and captures its resulting content into a string, which is returned. A *def* is Mako terminology for a reusable block of template code wrapped in a ``<%def>`` tag that behaves a bit like a function in Python. You’ll learn about defs and the ``capture()`` function later in the chapter. ``caller`` This is a “mini” namespace created when using the ``<%call>`` tag to define a “def call with content.” You don’t deal with ``caller`` in this book, but it is well documented at http://www.makotemplates.org/docs/documentation.html#defs_defswithcontent if you are interested. ``UNDEFINED`` This is an instance of ``mako.runtime.Undefined`` that raises an exception when its ``__str__()`` method is called. It is used when you use a variable in a template without assigning it a value. If you see an ``UNDEFINED``, it is likely that you mistyped a variable name or forgot to pass a particular variable to a template. .. index :: single: pageargs dictionary (Mako) ``pageargs`` This dictionary can be specified with the ``<%page>`` tag and tells templates the arguments that the ``body()`` def takes. You’ll look at the ``body()`` def and its use in template inheritance chains later in the book, but for details of ``pageargs``, consult the Mako documentation at http://www.makotemplates.org/docs/documentation.html#namespaces_body. .. index :: single: runtime built-ins; Mako templating language Three very useful methods of the context object are ``get()``, ``keys()``, and ``write()``. Here’s an example demonstrating how they are each used: :: <% context.write('Here is an example:
') %>
% for key in context.keys():
The key is ${key}, the value is ${str(context.get(key))}.
% endfor
Here is an example:
The key is all, the value is <built-in function all>.
The key is help, the value is Type help() for interactive help, or help(object) for help about object..
The key is vars, the value is <built-in function vars>.
The key is SyntaxError, the value is <type 'exceptions.SyntaxError'>.
The key is session, the value is {}.
The key is unicode, the value is <type 'unicode'>.
The key is sorted, the value is <built-in function sorted>.
...
.. index ::
single: methods of; context object (Mako)
The two important things to realize are that writing output with ``context.write()`` has the same effect as using ``${}`` and that any variables that can be used in a template can be accessed with ``context.get()``.
Separation of Logic and View
----------------------------
.. index ::
single: separating logic code and view code; Mako templating language
The greeting example you have been using so far is rather artificial because you could have just put your name directly into the template. Real web applications respond to data from various sources, so let’s make our example slightly more realistic by retrieving the name of the visitor from the query string on each request. If no query string is present, you’ll just use ``Visitor`` as the name.
::
def index(self):
c.name = request.params.get('name', 'Visitor')
return render('/greeting.html')
If you were now to visit http://localhost:5000/greeting/index?name=Pylons+Developer, you would see the same greeting as the first example.
This is a much more realistic example. Here the controller does some processing based on some logic and then passes relevant information to the template to display. In this setup, the template represents a *view* of the data in the Model View Controller architecture, and in line with this architecture, it is generally considered best practice to keep logic code in your controller and use Python only in your template to assist with rendering the information passed by the controller.
Some templating languages take the separation of logic code and view code to extremes and actively prohibit any sort of data processing in the template. Although this might be good practice, it can be sometimes be terribly frustrating when you want to do something simple if the templating language prevents you from doing it. Mako takes the view that the developer knows best and therefore provides some powerful templating tools and the ability to embed Python code in the template. It is then up to you as a developer to decide how much to use the tools Mako provides.
.. index ::
single: separating logic code and view code; Mako templating language
Here is the same example written slightly differently just to demonstrate that you can put simple logic in templates if you really need to do so. Here’s the action:
::
def index(self):
return render('/greeting.html')
and here’s the new template:
::
Hello ${request.params.get('name', 'Visitor')}!
Security Considerations and WebHelpers ====================================== .. index :: single: overview of; Mako templating language One point to watch out for when you are using any data from the Web in a template is that a malicious user might put HTML characters in the data. If, for example, you visit the URL http://localhost:5000/greeting/index?name=Ja%3Cb%3Em%3C%2Fb%3Ees, the value of ``request.params['name']`` would be ``James``, and if Mako didn’t apply any special escaping, this value would be rendered, resulting in the ``m`` being made bold in the HTML rendered by the browser. .. index :: single: cross-site scripting (XSS) attacks In itself this might not seem like a big problem, but actually it opens your web application up to so-called cross-site scripting (XSS) attacks. For example, a malicious user could insert JavaScript into your page to replace some of your own content to trick the user of the page into giving away information or visiting a site they didn’t intend to because they thought the content on the page was generated by you. This is a real risk for many websites today, so it is well worth being aware of. Pylons protects you from making this mistake by automatically escaping all values rendered by Mako. If you look at your project’s ``config/environment.py`` again, you will see that the full configuration for Mako looks like this: :: # Create the Mako TemplateLookup, with the default autoescaping config['pylons.app_globals'].mako_lookup = TemplateLookup( directories=paths['templates'], module_directory=os.path.join(app_conf['cache_dir'], 'templates'), input_encoding='utf-8', output_encoding='utf-8', imports=['from webhelpers.html import escape'], default_filters=['escape']) .. index :: single: webhelpers.html.escape function The last argument, ``default_filters``, means that all output is filtered through the ``webhelpers.html.escape`` function, which automatically applies HTML escaping to make the content safe. .. index :: single: webhelpers.html.literal() object Of course, sometimes you want to pass data to Mako and have it treated as HTML. To do this, you have to wrap the content in a ``webhelpers.html.literal()`` object. A ``literal`` is a special type derived from Python’s built-in ``unicode`` type. When the ``escape()`` function finds a ``literal``, it doesn’t escape it. .. index :: single: overview of; Mako templating language To demonstrate these features, update the ``greeting.html`` template so it looks like this: ::${c.greeting} ${c.name}!
Rather than using the ``webhelpers.html.literal`` object directly, most Pylons developers prefer to import it into their project’s ``lib/helpers.py`` file so that it can be accessed as ``h.literal`` in controllers. Update the ``lib/helpers.py`` file to include this import: :: """Helper functions Consists of functions to typically be used within templates, but also available to Controllers. This module is available to both as 'h'. """ # Import helpers as desired, or define your own, ie: # from webhelpers.html.tags import checkbox, password from webhelpers.html import literal Now import the ``helpers`` module into your controller as ``h`` by adding this at the top of ``controllers/greeting.py``: :: import templatedemo.lib.helpers as h Finally, change the ``index()`` action of the controller to look like this: :: def index(self): c.greeting = h.literal('Welcome') c.name = request.params.get('name', 'Visitor') return render('/greeting.html') .. index :: single: overview of; Mako templating language Now visit http://localhost:5000/greeting/index?name=Ja%3Cb%3Em%3C%2Fb%3Ees, and you will see that the HTML wrapped in ``literal()`` is rendered as an HTML literal, whereas the data passed to Mako from the ``request`` object is correctly escaped and the ``<`` and ``>`` characters are rendered correctly. Writing Your Own Helpers ------------------------ .. index :: single: writing helpers to use HTML literals; Mako templating language As of WebHelpers 0.6, all the HTML helper functions automatically return ``literal()`` objects, described earlier, so that their return values are treated as HTML. If you have created your own helper functions for a previous version of Pylons and try to use them with a Pylons 0.9.7 application, you will probably be surprised to find that all the output is escaped. You can solve this problem by modifying the helper functions to return an HTML ``literal`` object instead of a Python ``unicode`` or ``str`` object. When writing or upgrading helper functions to use HTML literals, you should be careful that you don’t accidentally introduce security holes. For example, consider this function: :: from webhelpers.html import literal def emphasize(value): return literal(''+value+'') Imagine you used this in your greeting action like this: :: c.name = emphasize(request.params.get('name', 'Visitor')) .. index :: single: writing helpers to use HTML literals; Mako templating language You have introduced a security hole because the ``James`` string is concatenated with the ```` and ```` strings in the ``emphasize()`` helper, and the whole string ``James`` is marked as a literal. The ```` and ```` tags now pass through the ``escape()`` function and through to the HTML document. This is not the behavior you want. Instead, the ``emphasize()`` function should be written like the following so the value itself isn’t accidentally marked as an HTML literal: :: def emphasize(value): return literal('') + value + literal('') To avoid the problem, WebHelpers 0.6 introduced an ``HTML`` object that can be used for generating HTML fragments in a safe way. Here is the ``emphasize`` helper written using the ``HTML`` object: :: def emphasize(value): return HTML.em(value) You can also nest HTML objects; the following would also wrap the value in a ```` tag: :: def emphasize(value): return HTML.span(HTML.em(value)) You can also add HTML attributes as keyword arguments to ``HTML``. Where an attribute name is a reserved word in Python, you should add ``_`` to the end of the argument. For example, here is a ```` tag with an ``id`` attribute of ``first`` and a ``class`` attribute of ``highlight``: :: def emphasize(value): return HTML.span(HTML.em(value), id='first', class_='highlight') Calling ``emphasize('James')`` would return a ``literal`` object representing the Unicode string ``u'Ja<m>es'`` with the HTML characters from the argument correctly escaped. .. index :: single: writing helpers to use HTML literals; Mako templating language See the WebHelpers documentation for more information at http://docs.pylonshq.com/thirdparty/webhelpers/html/html/. Applying Filters in Templates ----------------------------- .. index :: single: applying filters in templates; Mako templating language The ``escape()`` function set up as a default filter in ``config/environment.py`` is applied to all Mako output, but you can also apply filters to specific Mako output by using Mako’s ``|`` operator within a ``${}`` expression in a template. .. index :: single: built-in escape functions; Mako templating language The built-in escape functions are as follows: ``u`` This produces URL escaping, provided by ``urllib.quote_plus(string.encode('utf-8'))``. ``h`` This produces HTML escaping, provided by ``cgi.escape(string, True)``. Note that this is *not* the same as the ``helpers`` module object ``h``, which is also available in templates. Mako knows when you are using ``h`` as a filter and when it is supposed to refer to your project’s ``helpers`` module. ``x`` This produces XML escaping. ``trim`` This produces whitespace trimming, provided by ``string.strip()``. ``entity`` This produces HTML entity references for applicable strings, derived from the ``htmlentitydefs`` module in the standard library. ``unicode`` This produces a Python Unicode string (this function is applied by default). ``decode.${c.greeting} ${c.name}!
The ``<%namespace>`` tag takes a ``file`` argument to specify the template you want to import and a ``name`` argument to specify the namespace under which the defs should be imported. You can then use the ``nav`` namespace to generate navigation links in the greetings template. .. index :: single: %(%namespace%) tag; Mako templating language Sometimes it is useful to have the components imported directly into the local namespace rather than a namespace of their own. This is possible too using this alternative syntax: :: <%namespace file="navigation.html" import="navigation_links" /> ${navigation_links('James', type='list', links=[ ['James','http://jimmyg.org'], ['Ben','http://groovie.org'], ['Philip',''], ])} When the ``import`` attribute is used, the ``name`` attribute is optional. You can also just use ``import="*"`` to import everything from another template or ``import="component1, component2"`` to specify specific components you want to import. The names imported by the ``import`` attribute take precedence over any names that exist within the current context. Namespaces can also import regular Python functions from modules as long as they accept an argument named ``context`` as their first argument. As an example, a module file ``my/module.py`` might contain the following callable: :: def write_greeting(context): context.write("hello world") A template can then use this module as follows: :: <%namespace name="my" module="my.module" /> ${my.write_greeting()} .. index :: single: %(%namespace%) tag; Mako templating language Note that the ``context`` argument is not needed in the call. When Mako generates the cached Python version, it creates a locally scoped callable, which is responsible for passing the ``context`` object in for you. The body() Def -------------- .. index :: single: body() def; Mako templating language There is one other important ``<%def>`` you will need to know about called the ``body()`` def. The ``body()`` def represents the whole of the body of the template, that is, any template code not wrapped in its own def. For example, if you had a template that looked like this, the ``12:00pm`` line would be in the ``body()`` def. :: <%def name="test()">Hello World!%def> 12:00pm You can see this in action by using this template in another one. Imagine the previous template was saved as ``greeting_and_time.html``. You could create another template like this to use its functionality under the namespace ``other``: :: <%namespace name="other" file="/greeting_and_time.html" /> The greeting is ${other.test()} The time is ${other.body()} Notice how the calling body method is effectively just like a normal ``<%def>`` but without the opening and closing ``<%def>`` tags needing to be specified. The output is as you would expect: :: The greeting is Hello World! The time is 12:00pm .. index :: single: body() def; Mako templating language Being able to access the body of a template is really useful when you are using template chains in an inheritance structure. Let’s look at this in the next section. Template Inheritance Chains =========================== .. index :: single: overview of; Mako templating language The real value of templating languages isn’t so much that they help you mix and match Python and plain text in a more efficient manner but that so much of their functionality can be reused effectively in other pages. You’ve already seen how you can create reusable components using ``<%def>`` blocks and then import them into other templates using the ``<%namespace>`` tag, but Mako also provides facilities to enable you to structure your templates so that derived templates can inherit functionality from a base template. Simple Inheritance ------------------ .. index :: single: simple inheritance; Mako templating language Using a template chain in Mako is best explained with an example. The following is a base template named ``base.html``, which defines some HTML and a footer but also has two defs, ``self.title()`` and ``self.body()``. Save this template as ``base.html`` in ``templatedemo/templates``: ::${c.greeting} ${c.name}!
.. index :: single: simple inheritance; Mako templating language Save this new version of ``greeting.html``. The ``index()`` action of the ``greeting`` controller should still look like this: :: def index(self): c.greeting = h.literal('Welcome') c.name = request.params.get('name', 'Visitor') return render('/greeting.html') If you visit http://localhost:5000/greeting/index in your browser again, you will see the following HTML rendered: ::Welcome Visitor!
Let’s think about what is going on to produce this HTML. Because ``greeting.html`` inherits from the ``base.html`` control for rendering passes directly to the ``base.html body()`` def. The ```` line is rendered first, followed by all the other characters until ``${self.title()}`` is called. .. index :: single: simple inheritance; Mako templating language In the context of rendering a normal template, ``self`` would refer to the template itself, but in the context of an inheritance chain like this one, ``self`` always refers to the template at the bottom of the inheritance chain, which is always the template that was originally specified in the call to ``render()``, in this case, ``greeting.html``. This means that although you are rendering the ``base.html body()`` def, ``${self.title()}`` refers to the ``title()`` def in ``greeting.html``. This renders the ``Greeting`` text, which appears in the page title. Once the title is rendered, control passes back to the ``base.html`` template, and more HTML is rendered until ``${self.body()}`` is reached. Once again, ``self`` refers to ``greeting.html``, so the ``body()`` def of ``greeting.html`` is rendered. Finally, control passes back to ``base.html`` to render the footer, and the whole page is rendered. As you can imagine, being able to structure your templates like this is really useful because it means you can now create multiple templates based on ``base.html`` without having to duplicate its content in each child template. By using defs in the way you used ``title()``, you can create regions that can be replaced in child templates. These don’t just have to contain static text; they can also contain navigation elements, CSS, JavaScript, section headings, or any other content you like. When you start the SimpleSite tutorial, you’ll use inheritance chains to create a full-featured site. .. caution :: If you are following the Mako documentation, you should be aware that Mako describes the template at the top of the chain (``base.html`` in our example) as being the bottom-most template and the template at the bottom as being the top-most template, so you need to be aware of the slightly confusing terminology. .. index :: single: simple inheritance; Mako templating language In the previous example, you used the ``self`` namespace to effectively mean “use the def from the template furthest down the inheritance chain.” Mako also provides two related namespaces called ``next`` and ``parent``, which are especially useful if you have more than two templates involved in an inheritance chain. Next Namespace -------------- .. index :: single: next namespace; Mako templating language Imagine the greeting template you’ve been using is actually part of the user administration section of a site. This site might also need some section links to allow the user to navigate around the section, but if these links were put in the ``base.html`` template, they would appear on all pages in the site, not just in the user administration section. You could put the links in the ``greeting.html`` template, but then you would also have to duplicate them in other templates in the same section. You could do this by keeping the links in a namespace and simply calling the def in each template rather than duplicating the code each time, but Mako provides a better solution. It turns out that you aren’t limited to two templates in an inheritance chain; you can have as many templates as you like. Rather than inheriting the ``greeting.html`` template from the ``base.html`` template, let’s create a new template specifically for the user administration section; call it ``section.html``, and save this file in the ``templatedemo/templates`` directory with the following content (there is a deliberate mistake in this template, though, so you might want to read on first): :: <%inherit file="/base.html"/> <%namespace file="/navigation.html" import="navigation_links" /> ${navigation_links('Admin Home', links=[ ('Admin Home', '/admin'), ('Settings', '/admin/settings'), ('Sign Out', '/admin/signout'), ])} ${self.body()} <%def name="title()">User Administration%def> Notice that this template inherits from ``base.html`` and that you are still using the ``navigation.html`` template you created earlier to do the hard work of creating the links. For the ``greeting.html`` template to use this template, you need to change its ``<%inherit>`` tag to look like this: :: <%inherit file="/section.html"/>\ If you refresh the browser, you will see that the content hasn’t changed! This might surprise you, so let’s think about what’s happened. You call ``render()`` to render ``greeting.html``, and control is passed to the ``section.html body()`` def, but this template is inherited from ``base.html``, so control passes to the ``base.html body()`` def. Once again, HTML is rendered until ``${self.title()}`` is reached. Remember that ``self`` refers to the *last* template in the chain, in this case, ``greeting.html``, so it is the ``greeting.html`` ``title()`` def and ``body()`` def that are rendered, not the ones in ``section.html``. .. index :: single: next namespace; Mako templating language To solve this problem, you need to use Mako’s ``next`` namespace. ``next`` is similar to ``self`` but refers to the next template in the chain, not the last one. To use ``next``, you’ll need to change all the references to ``${self.title()}`` and ``${self.body()}`` in ``base.html`` and ``section.html`` to use ``${next.title()}`` and ``${next.body()}``, respectively. Once you’ve updated the templates, they behave as you expect. When ``${next.title()}`` is reached, the ``title()`` def from ``section.html`` is rendered. Control is passed back to ``base.html`` until ``${next.body()}`` is reached; then the ``body()`` def of ``section.html`` is rendered, producing the navigation links. When ``${next body()}`` is reached in ``section.html``, the ``body()`` def from ``greeting`` is rendered. When it is finished, control passes back to ``section.html`` and then back to ``base.html`` to finish off the rendering. Figure 5-2 shows the result. .. figure :: 9349f0502.png :target: _images/9349f0502.png :scale: 70 :alt: Figure 5-2. Greeting produced with a template inheritance chain Figure 5-2. Greeting produced with a template inheritance chain If the ``section.html`` template didn’t have a ``title()`` def, the call to ``${next.title()}`` in ``base.html`` would have rendered the ``title()`` def in ``greeting.html`` instead. .. index :: single: next namespace; Mako templating language Middle templates such as ``section.html`` are normally used for sections of the site in this way with base templates such as ``base.html`` containing content that applies to every page and child templates such as ``greeting.html`` containing only page-specific information. Of course, if you have a large site, it might make sense to have more than one middle template so that you can implement subsections or different page layouts within a section. The inheritance technique is very flexible. Parent Namespace ---------------- .. index :: single: parent namespace; Mako templating language In the same way that the ``next`` namespace allows you to refer to a def in the namespace of the child template immediately below it, Mako also provides a ``parent`` namespace that allows a child template to refer to a def in the parent template immediately above it. This is useful if you want a child template to be able to control where in a parent template its content is inserted. .. note :: Using the ``parent`` namespace might remind you of using ``super`` in a derived class to access a method in a base class in a normal Python inheritance structure. The two are similar, but in Python there is no equivalent to the ``next`` namespace; that is, you cannot access a child method from a parent class. Let’s change the way the ``title()`` def works so that ``greeting.html`` can decide whether to include the content from the ``section.html body()`` def. The first thing you need to do is change ``base.html`` so that it calls ``${self.title()}`` rather than ``${next.title()}``. This means that when the title is rendered, control for rendering the def will pass to ``greeting.html``, bypassing ``section.html``. ::