Ferris uses the Jinja2 template engine and adds a few helper functions and filters, some layouts, and a theme system.
Templates are stored in /app/templates/[handler]/[prefix_][action].html. So if you had a handler named Bears and an action named picnic, you would create a file named /app/templates/bears/picnic.html. If you have a handler named Pages and an action named view and the prefix is mobile, you would create the template at /app/template/pages/mobile_view.html.
Usually, a template will inherit from a layout and provide one or more blocks with content:
{% extends "layouts/default.html" %}
{% block layout_content %}
<div> Hello! </div>
{% endblock %}
This is optional, a template can easily skip extending a layout and provide its own content:
<div> This works too! </div>
Also, a template can inherit from any other valid template:
{% extends "posts/list.html" %}
{% block post_title %}
<h1 class='super-large'>{{post.title}}</h1>
{% endblock %}
Layouts reside inside of app/templates/layouts and serve as the base templates for regular templates to inherit from.
For example, here’s a layout name large_text.html:
<h1>{% block content %}{% endblock %}</h1>
Here’s a template that inherits from it:
{% extends "layouts/large_text.html" %}
{% block content %}Yeah, Big Text!{% endblock %}
For more info on template inheritence, see the jinja2 docs on inheritance.
Ferris provides two standard layouts
Located at layouts/default.html, the default layout provides a simple Twitter Bootstrap layout and a few blocks.
Text inside of the <title> tag.
Markup inside of the <head> tag, useful for adding scripts and stylesheets.
Everything inside the body tag, wraps layout_content, layout_before_content, and layout_after_content
Content inside of the <div class='container'> tag, the common spot for overriding and placing content.
Content before the <div class='container'> tag
Content after the <div class='container'> tag
Located at layouts/admin.html, the admin layout is used by the :doc:scaffolding and provides a layout with a side bar and navigation bar.
It contains all of the same blocks as the default layout, plus:
Contains the top navigation bar.
Contains layout_header, layout_sidebar, and layout_content
Contains the breadcrumb and sits between layout_nav_bar and the two columns.
Contains the action pallete (or any other content to be placed in the sidebar).
Elements are typically located in app/templates/elements or for very specific elements app/templates/[handler]/elements. There’s nothing special about element other than just the organization and the idea.
Take this element species.html for example:
<div>
<h1>{{species.name}}</h1>
<h2>From {{species.planet}}</h2>
<p>{{species.description}}</p>
</div>
And this template that uses the element:
{% for species in species_list %}
{% include "elements/species.html" with context %}
{% endfor %}
Includes the scripts and stylesheets needed for jquery ui.
Includes the debug toolbox (click the small icon in the bottom-right corner).
Includes the chosen javascript library and inserts it on all select boxes on the page.
Includes the fancybox javascript library.
Includes the bootstrap datepicker javascript library.
Macros are usually located in app/templates/macros/[name].html, although some things choose app/templates/[name]/macros.html. Either way is valid. The first makes sense when macros are more general, whereas the second makes sense when macros are used only in one set of templates.
Macros are just files that contain a collection of jinja2 macros.
Themes are a collection of templates, elements, and macros that can override those in the root or default theme. Themes are located in app/templates/themes/[name] and their directory structure mirrors that of the root app/templates folder.
For example, if you have a root template structure like this:
* posts
* list.html
* view.html
* elements
* post.html
And you created a new theme called mobile under app/templates/themes/mobile and created the following directory structure:
* posts
* view.html
* elements
* post.html
If you switch the theme to mobile, then the template engine will use the posts/view.html and elements/post.html templates from the mobile folder, however because we did not specify a posts/list.html in the mobile theme, it will use the posts/list.html in the root theme. In short, if a theme doesn’t have a template it will fallback and use the root theme’s template.
You can set the theme using Handler.theme.
Data is provided via set() and get() in Handler:
self.set(species="Raxacoricofallapatorian")
This data can now be accessed by name in the template:
This is a {{species}}!
Of course, more complex data can be provided such as a Model instance:
self.set(species=Species.find_by_planet('Gallifrey'))
Properties on that object can be accessed in the template:
The primary species of the planet {{species.planet}} is {{species.name}}.
Ferris adds a few useful items to the template context.
Uses ferris.json_util to serialize an object to JSON. Can also be used as a filter.
Maps to google.appengine.ext.ndb
The ferris object provides:
Maps to google.appengine.api.users
The handler object provides:
The name of the current handler.
Maps to ferris.core.Handler.uri() to generate urls.
The current user.
Most of these map 1:1 to their python equivalents.