App Templating API¶
Last Updated: May 2017
The pages of a Tethys app are created using the Django template language. This provides an overview of important Django templating concepts and introduces the base templates that are provided to make templating easier.
Django Templating Concepts¶
The Django template language allows you to create dynamic HTML templates and minmizes the amount of HTML you need to write for your app pages. This section will provide a crash course in Django template language basics, but we highly recommend a review of the Django Template Language documentation.
Tip
Review the Django Template Language to get a better grasp on templating in Tethys.
Variables¶
In Django templates, variables are denoted by double curly brace syntax: {{ variable }}
. The variable expression will be replaced by the value of the variable. Dot notation can be used access attributes of a variable: {{ variable.attribute }}
.
Examples:
# Examples of Django template variable syntax
{{ variable }}
# Access items in a list or tuple using dot notation
{{ list.0 }}
# Access items in a dictionary using dot notation
{{ dict.key }}
# Access attributes of objects using dot notation
{{ object.attribute }}
Hint
See Django template Variables documentation for more information.
Filters¶
Variables can be modified by filters which look like this: {{ variable|filter:argument }}
. Filters perform modifying functions on variable output such as formatting dates, formatting numbers, changing the letter case, and concatenating multiple variables.
Examples:
# The default filter can be used to print a default value when the variable is falsy
{{ variable|default:"nothing" }}
# The join filter can be used to join a list with a the separator given
{{ list|join:", " }}
Hint
Refer to the Django Filter Reference for a full list of the filters available.
Template Inheritance¶
One of the advantages of using the Django template language is that it provides a method for child templates to extend parent templates, which can reduce the amount of HTML you need to write. Template inheritance is accomplished using two tags, extends
and block
. Parent templates provide blocks
of content that can be overridden by child templates. Child templates can extend parent templates by using the extends
tag. Calling the block
tag of a parent template in a child template will override any content in that block
tag with the content in the child template.
Hint
The Django Template Inheritance documentation provides an excellent example that illustrates how inheritance works.
Base Templates¶
There are two layers of templates provided for Tethys app development. The app_base.html
or any of its derivatives (See Additional Base Templates) from which all Tethys apps inherit, and the base.html
at the app level from which all pages in an app project can inherit.
The app_base.html
template provides the HTML skeleton for all Tethys app templates, which includes the base HTML structural elements (e.g.: <html>
, <head>
, and <body>
elements), the base style sheets and JavaScript libraries, and many blocks for customization.
All Tethys app projects also include a base.html
template that inherits from the app_base.html
template.
App developers are encouraged to use the base.html
file as the base template for all of their templates within an app, rather than extending the app_base.html
file directly. The base.html
template is easier to work with, because it includes only the blocks that will be used most often from the app_base.html
template or its derivatives (See Additional Base Templates). However, all of the blocks that are available from app_base.html
template or its selected derivative template will also be available for use in the base.html
template and any templates that extend it.
Many of the blocks in the template correspond with different portions of the app interface. Figure 1 provides a graphical explanation of these blocks. An explanation of all the blocks provided in the app_base.html
and base.html
templates can be found in the section that follows.
Blocks¶
This section provides an explanation of the blocks are available for use in child templates of either the app_base.html
or the base.html
templates.
htmltag¶
Override the <html>
element open tag.
Example:
{% block htmltag %}<html lang="es">{% endblock %}
headtag¶
Add attributes to the <head>
element.
Example:
{% block headtag %}style="display: block;"{% endblock %}
meta¶
Override or append <meta>
elements to the <head>
element. To append to existing elements, use block.super
.
Example:
{% block meta %}
{{ block.super }}
<meta name="description" value="My website description" />
{% endblock %}
title¶
Change title for the page. The title is used as metadata for the site and shows up in the browser in tabs and bookmark names.
Example:
{% block title %}{{ block.super }} - My Sub Title{% endblock %}
links¶
Add content before the stylesheets such as rss feeds and favicons. Use block.super
to preserve the default favicon or override completely to specify custom favicon.
Example:
{% block links %}
<link rel="shortcut icon" href="/path/to/favicon.ico" />
{% endblock %}
import_gizmos¶
The import_gizmos block allows you register gizmos to be added to your page so that the dependencies load properly.
Example:
{% block import_gizmos %}
{% import_gizmo_dependency map_view %}
{% endblock %}
styles¶
Add additional stylesheets to the page. Use block.super
to preserve the existing styles for the app (recommended) or override completely to use your own custom stylesheets.
Example:
{% block styles %}
{{ block.super }}
<link href="/path/to/styles.css" rel="stylesheet" />
{% endblock %}
global_scripts¶
Add JavaScript libraries that need to be loaded prior to the page being loaded. This is a good block to use for libraries that are referenced globally. The global libraries included as global scripts by default are JQuery and Bootstrap. Use block.super
to preserve the default global libraries.
Example:
{% block global_scripts %}
{{ block.super }}
<script src="/path/to/script.js" type="text/javascript"></script>
{% endblock %}
bodytag¶
Add attributes to the body
element.
Example:
{% block bodytag %}class="a-class" onload="run_this();"{% endblock %}
app_content_wrapper_override¶
Override the app content structure completely. The app content wrapper contains all content in the <body>
element other than the scripts. Use this block to override all of the app template structure completely.
Override Eliminates:
app_header_override, app_navigation_toggle_override, app_icon_override, app_icon, app_title_override, app_title, exit_button_override, app_content_override, flash, app_navigation_override, app_navigation, app_navigation_items, app_content, app_actions_override, app_actions.
Example:
{% block app_content_wrapper_override %}
<div>
<p>My custom content</p>
</div>
{% endblock %}
app_header_override¶
Override the app header completely including any wrapping elements. Useful for creating a custom header for your app.
Override Eliminates:
app_navigation_toggle_override, app_icon_override, app_icon, app_title_override, app_title, exit_button_override
app_icon_override¶
Override the app icon in the header completely including any wrapping elements.
Override Eliminates:
app_icon
app_icon¶
Override the app icon <img>
element in the header.
Example:
{% block app_icon %}<img src="/path/to/icon.png">{% endblock %}
app_title_override¶
Override the app title in the header completely including any wrapping elements.
Override Eliminates:
app_title
app_title¶
Override the app title element in the header.
Example:
{% block app_title %}My App Title{% endblock %}
app_content_override¶
Override only the app content area while preserving the header. The navigation and actions areas will also be overridden.
Override Eliminates:
flash, app_navigation_override, app_navigation, app_navigation_items, app_content, app_actions_override, app_actions
flash¶
Override the flash messaging capabilities. Flash messages are used to display dismissible messages to the user using the Django messaging capabilities. Override if you would like to implement your own messaging system or eliminate functionality all together.
app_content¶
Add content to the app content area. This should be the primary block used to add content to the app.
Example:
{% block app_content %}
<p>Content for my app.</p>
{% endblock %}
after_app_content¶
Use this block for adding elements after the app content such as Bootstrap modals (Bootstrap modals will not work properly if they are placed in the main app_content
block).
Example:
{% block after_app_content %}
{% gizmo my_modal %}
{% endblock %}
app_actions_override¶
Override app content elements including any wrapping elements.
app_actions¶
Override or append actions to the action area. These are typically buttons or links. The actions are floated right, so they need to be listed in right to left order.
Example:
{% block app_actions %}
<a href="" class="btn btn-default">Next</a>
<a href="" class="btn btn-default">Back</a>
{% endblock %}
scripts¶
Add additional JavaScripts to the page. Use block.super
to preserve the existing scripts for the app (recommended) or override completely to use your own custom scripts.
Example:
{% block scripts %}
{{ block.super }}
<script href="/path/to/script.js" type="text/javascript"></script>
{% endblock %}
base.html¶
The base.html
is the base template that is used directly by app templates. This file is generated in all new Tethys app projects that are created using the scaffold. The contents are provided here for reference.
All of the blocks provided by the base.html
template are inherited from the app_base.html
template. The base.html
template is intended to be a simplified version of the app_base.html
template, providing only the the blocks that should be used in a default app configuration. However, the blocks that are excluded from the base.html
template can be used by advanced Tethys app developers who wish customize parts or all of the app template structure.
See the Blocks section for an explanation of each block.
{% extends "tethys_apps/app_base.html" %}
{% load static %}
{% block title %}- {{ tethys_app.name }}{% endblock %}
{% block styles %}
{{ block.super }}
<link href="{% static 'new_template_app/css/main.css' %}" rel="stylesheet"/>
{% endblock %}
{% block app_icon %}
{# The path you provided in your app.py is accessible through the tethys_app.icon context variable #}
<img src="{% if 'http' in tethys_app.icon %}{{ tethys_app.icon }}{% else %}{% static tethys_app.icon %}{% endif %}" />
{% endblock %}
{# The name you provided in your app.py is accessible through the tethys_app.name context variable #}
{% block app_title %}{{ tethys_app.name }}{% endblock %}
{% block app_navigation_items %}
<li class="title">App Navigation</li>
<li class="active"><a href="">Home</a></li>
<li><a href="">Jobs</a></li>
<li><a href="">Results</a></li>
<li class="title">Steps</li>
<li><a href="">1. The First Step</a></li>
<li><a href="">2. The Second Step</a></li>
<li><a href="">3. The Third Step</a></li>
<li class="separator"></li>
<li><a href="">Get Started</a></li>
{% endblock %}
{% block app_content %}
{% endblock %}
{% block app_actions %}
{% endblock %}
{% block scripts %}
{{ block.super }}
<script src="{% static 'new_template_app/js/main.js' %}" type="text/javascript"></script>
{% endblock %}
app_base.html¶
This section provides the complete contents of the app_base.html
template. It is meant to be used as a reference for app developers, so they can be aware of the HTML structure underlying their app templates.
{% load static tethys_gizmos terms_tags analytical%}
<!DOCTYPE html>
{# Allows custom attributes to be added to the html tag #}
{% block htmltag %}
<!--[if IE 7]> <html lang="en" class="ie ie7"> <![endif]-->
<!--[if IE 8]> <html lang="en" class="ie ie8"> <![endif]-->
<!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en" > <!--<![endif]-->
{% endblock %}
{# Allows custom attributes to be added to the head tag #}
<head {% block headtag %}{% endblock %}>
{% analytical_head_top %}
{% comment "meta explanation" %}
Add custom meta tags to the page. Call block.super to get the default tags
such as charset, viewport and generator.
Example:
{% block meta %}
{{ block.super }}
<meta name="description" value="My website description" />
{% endblock %}
{% endcomment %}
{% block meta %}
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="Django" />
{% endblock %}
{% comment "title explanation" %}
Add a custom title to the page by extending the title block. Call block.super
to get the default page title.
Example:
{% block title %}My Subtitle - {{ block.super }}{% endblock %}
{% endcomment %}
<title>
{% if site_globals.site_title %}
{{ site_globals.site_title }}
{% elif site_globals.brand_text %}
{{ site_globals.brand_text }}
{% else %}
Tethys
{% endif %}
{% block title %}{% endblock %}
</title>
{% comment "links explanation" %}
The links block allows you to add additional content before the stylesheets
such as rss feeds and favicons in the same way as the meta block.
{% endcomment %}
{% block links %}
<link rel="shortcut icon" href="{% if site_globals.favicon and 'http' in site_globals.favicon %}{{ site_globals.favicon }}{% elif site_globals.favicon %}{% static site_globals.favicon %}{% else %}{% static 'tethys_portal/images/default_favicon.png' %}{% endif %}" />
{% endblock %}
{% comment "import_gizmos explanation" %}
The import_gizmos block allows you register gizmos to be added to your
page so that the dependencies load properly.
Example:
{% block import_gizmos %}
{% import_gizmo_dependency map_view %}
{% endblock %}
{% endcomment %}
{% block import_gizmos %}
{% endblock %}
{% comment "styles explanation" %}
The styles block allows you to add additional stylesheets to the page in
the same way as the meta block. Use block.super to include the default
stylesheets before or after your own.
Example:
{% block styles %}
{{ block.super }}
<link href="{% static 'custom/css/foo.css' %}" rel="stylesheet" />
{% endblock %}
{% endcomment %}
{% block styles %}
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/{{ tethys.bootstrap.version }}/css/bootstrap.min.css" integrity="{{ tethys.bootstrap.css_integrity }}" crossorigin="anonymous">
{% block app_base_styles %}
<link href="{% static 'tethys_apps/css/app_base.min.css' %}" rel="stylesheet" />
{% endblock %}
{% if tethys_app.enable_feedback %}
<link href="{% static 'tethys_apps/css/feedback.css' %}" rel="stylesheet" />
{% endif %}
{% gizmo_dependencies global_css %}
{% endblock %}
{% block global_scripts %}
<script src="//code.jquery.com/jquery-{{ tethys.jquery.version }}.min.js" integrity="{{ tethys.jquery.integrity }}" crossorigin="anonymous"></script>
<script src="//stackpath.bootstrapcdn.com/bootstrap/{{ tethys.bootstrap.version }}/js/bootstrap.min.js" integrity="{{ tethys.bootstrap.js_integrity }}" crossorigin="anonymous"></script>
{% gizmo_dependencies global_js %}
{% endblock %}
{% block session_timeout_modal %}
{% include 'session_security/all.html' %}
<link href="{% static 'tethys_portal/css/session_security_override.css' %}" rel="stylesheet" />
{% endblock %}
{% analytical_head_bottom %}
</head>
{# Allows custom attributes to be added to the body tag #}
<body {% block bodytag %}{% endblock %}>
{% analytical_body_top %}
{% block app_content_wrapper_override %}
<div id="app-content-wrapper" class="show-nav">
{% block app_header_override %}
<div id="app-header" class="clearfix">
<div class="tethys-app-header" style="background: {{ tethys_app.color|default:'#1b95dc' }};">
<div id="nav-title-wrapper">
{% block app-navigation-toggle-override %}
<a href="javascript:void(0);" class="toggle-nav">
<div></div>
<div></div>
<div></div>
</a>
{% endblock %}
{% block app_icon_override %}
<div class="icon-wrapper">
{% block app_icon %}<img src="{% if tethys_app.icon %}{% if 'http' in tethys_app.icon %}{{ tethys_app.icon }}{% else %}{% static tethys_app.icon %}{% endif %}{% else %}{% static 'tethys_apps/images/default_app_icon.gif' %}{% endif %}" />{% endblock %}
</div>
{% endblock %}
{% block app_title_override %}
<div class="app-title-wrapper">
<span class="app-title">{% block app_title %}{{ tethys_app.name }}{% endblock %}</span>
</div>
{% endblock %}
</div>
{% block header_buttons_override %}
<div id="header-buttons-wrapper">
{% block header_buttons %}
{% endblock %}
{% block login_button_override %}
{% if not request.user.is_authenticated %}
<div class="header-button login-button">
<a href="javascript:void(0);" onclick="TETHYS_APP_BASE.exit_app('{% url 'accounts:login' %}?next={{request.path}}');"data-toggle="tooltip" data-placement="bottom" title="Log In">Log In</a>
</div>
{% endif %}
{% endblock %}
{% block settings_button_override %}
{% if request.user.is_staff %}
<div class="header-button settings-button">
<a href="javascript:void(0);" onclick="TETHYS_APP_BASE.exit_app('{% url 'admin:index' %}tethys_apps/tethysapp/{{ tethys_app.id }}/change/');" data-toggle="tooltip" data-placement="bottom" title="Settings"><span class="glyphicon glyphicon-cog"></span></a>
</div>
{% endif %}
{% endblock %}
{% block exit_button_override %}
<div class="header-button exit-button">
<a href="javascript:void(0);" onclick="TETHYS_APP_BASE.exit_app('{% url 'app_library' %}');"data-toggle="tooltip" data-placement="bottom" title="Exit">x</a>
</div>
{% endblock %}
</div>
{% endblock %}
</div>
</div>
{% endblock %}
{% block app_content_override %}
<div id="app-content">
{% block flash %}
{% if messages %}
<div class="flash-messages">
{% comment "flash_messages explanation" %}
Use the flash messages block to display temporary feedback to the user. Pass
a list of dictionaries called "flash_messages". Each dictionary should have the
keys "category" and "text". The category can be any of: "success", "info",
"warning", and "danger". The category is used to style the message. The text is
the text of the message to be displayed. The alerts that will be displayed are
dismissible. To create custom alerts, override the "flash" block.
{% endcomment %}
{% for message in messages %}
<div class="alert {% if message.tags %}{{ message.tags }}{% endif %} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
{% endblock %}
{# Off canvas navigation menu #}
{% block app_navigation_override %}
<div id="app-navigation">
{% block app_navigation %}
<ul class="nav nav-pills nav-stacked">
{% block app_navigation_items %}{% endblock %}
</ul>
{% endblock %}
</div>
{% endblock %}
{# App content starts here #}
{% block inner_app_content %}
<div id="inner-app-content">
{% block app_content %}{% endblock %}
{# App actions are fixed to the bottom #}
{% block app_actions_override %}
<div id="app-actions">
{% block app_actions %}{% endblock %}
<div id="app-actions-spacer"></div>
</div>
{% endblock %}
</div>
{% endblock %}
</div>
{% endblock %}
</div>
{% endblock %}
{% comment "after_app_content explanation" %}
Use this block for adding elements after the app content such as
bootstrap modals.
Example:
{% block after_app_content %}
{% gizmo my_modal %}
{% endblock %}
{% endcomment %}
{% block after_app_content %}
{% block modals %}
{% endblock %}
{% endblock %}
{% block terms-of-service-override %}
{% show_terms_if_not_agreed %}
{% endblock %}
{% block page_attributes_override %}
<div id="page-attributes" data-username="{{ user.username }}" style="display: none;"></div>
{% endblock %}
{% block content_dependent_styles %}
{% gizmo_dependencies css %}
{% endblock %}
{% block csrf_token %}
{% csrf_token %}
{% endblock %}
{% comment "scripts explanation" %}
Use this block for adding scripts. Call with block.super to include the default
scripts.
Example:
{% block scripts %}
{{ block.super }}
<script type="text/javascript" src="{% static 'custom/js/bar.js' %}"></script>
{% endblock %}
{% endcomment %}
{% block scripts %}
<script src="{% static 'tethys_apps/vendor/cookies.js' %}" type="text/javascript"></script>
{% block app_base_js %}
<script src="{% static 'tethys_apps/js/app_base.js' %}" type="text/javascript"></script>
{% endblock %}
{% if tethys_app.enable_feedback %}
<script src="{% static 'tethys_apps/js/feedback.js' %}" type="text/javascript"></script>
{% endif %}
{% gizmo_dependencies js %}
{% endblock %}
{% analytical_body_bottom %}
</body>
</html>
Additional Base Templates¶
Additional templates that inherit from the app_base.html
template have been added to Tethys to facilitate app customization. These templates include:
app_content_only.html¶
This template contains only the app content. Code referencing displays block other than the app_content
block will have no effect on this template. Override
, JavaScript
, and Style
blocks retain their regular behavior.
app_header_content.html¶
This template contains only the header and app content. Code referencing any display block other than the app_content
block or blocks contained in the app header (app_icon
, app_title
, or header_buttons
) will have no effect on this template. Override
, JavaScript
, and Style
blocks retain their regular behavior.
app_no_actions.html¶
This template is the same as normal app_base.html
, but with no app actions section. Code referencing the app_actions
block will have no effect on this template. Other blocks retain their regular behavior.
app_left_actions.html¶
This template is the same as app_header_content.html
with the actions bar on left.
app_right_actions.html¶
This template is the same as app_header_content.html
with the actions bar on right.
app_quad_split.html¶
This template is the same as app_header_content.html
but with a 2 x 2 Bootstrap Grid in the content area.
Instead of an app_content
block, this app uses the following four blocks:
app_content_tl: The app content that will be displayed in the top left section of the 2 x 2 grid.
app_content_tr: The app content that will be displayed in the top right section of the 2 x 2 grid.
app_content_bl: The app content that will be displayed in the bottom left section of the 2 x 2 grid.
app_content_br: The app content that will be displayed in the bottom right section of the 2 x 2 grid.
Example:
{% block app_content_tl %}
<p>Top left content for my app.</p>
{% endblock %}
{% block app_content_tr %}
<p>Top right content for my app.</p>
{% endblock %}
{% block app_content_bl %}
<p>Bottom left content for my app.</p>
{% endblock %}
{% block app_content_br %}
<p>Bottom right content for my app.</p>
{% endblock %}
app_three_columns.html¶
This template is the same as app_header_content.html
but with a three-column Bootstrap Grid in the content area.
Instead of an app_content
block, this app uses the following three blocks:
app_content_lc: The app content that will be displayed in the left column of the three-column grid.
app_content_mc: The app content that will be displayed in the middle column of the three-column grid.
app_content_rc: The app content that will be displayed in the right column of the three-column grid.
Example:
{% block app_content_lc %}
<p>Left column content for my app.</p>
{% endblock %}
{% block app_content_tr %}
<p>Middle column content for my app.</p>
{% endblock %}
{% block app_content_bl %}
<p>Right column content for my app.</p>
{% endblock %}
app_two_columns.html¶
This template is the same as app_header_content.html
but with a two-column Bootstrap Grid in the content area.
Instead of an app_content
block, this app uses the following two blocks:
app_content_lc: The app content that will be displayed in the left column of the two-column grid.
app_content_rc: The app content that will be displayed in the right column of the two-column grid.
Example:
{% block app_content_lc %}
<p>Left column content for my app.</p>
{% endblock %}
{% block app_content_bl %}
<p>Right column content for my app.</p>
{% endblock %}