Jinja

« Switching from other Template Engines | Tips and Tricks | Frequently Asked Questions »

Tips and Tricks

This part of the documentation shows some tips and tricks for Jinja2 templates.

Null-Master Fallback

Jinja2 supports dynamic inheritance and does not distinguish between parent and child template as long as no extends tag is visited. While this leads to the surprising behavior that everything before the first extends tag including whitespace is printed out instead of being igored, it can be used for a neat trick.

Usually child templates extend from one template that adds a basic HTML skeleton. However it’s possible put the extends tag into an if tag to only extend from the layout template if the standalone variable evaluates to false which it does per default if it’s not defined. Additionally a very basic skeleton is added to the file so that if it’s indeed rendered with standalone set to True a very basic HTML skeleton is added:

{% if not standalone %}{% extends 'master.html' %}{% endif -%}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<title>{% block title %}The Page Title{% endblock %}</title>
<link rel="stylesheet" href="style.css" type="text/css">
{% block body %}
  <p>This is the page body.</p>
{% endblock %}

Alternating Rows

If you want to have different styles for each row of a table or list you can use the cycle method on the loop object:

<ul>
{% for row in rows %}
  <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
</ul>

cycle can take an unlimited amount of strings. Each time this tag is encountered the next item from the list is rendered.

Highlighting Active Menu Items

Often you want to have a navigation bar with an active navigation item. This is really simple to achieve. Because assignments outside of blocks in child templates are global and executed before the layout template is evaluated it’s possible to define the active menu item in the child template:

{% extends "layout.html" %}
{% set active_page = "index" %}

The layout template can then access active_page. Additionally it makes sense to defined a default for that variable:

{% set navigation_bar = [
    ('/', 'index', 'Index'),
    ('/downloads/', 'downloads', 'Downloads'),
    ('/about/', 'about', 'About')
] -%}
{% set active_page = active_page|default('index') -%}
...
<ul id="navigation">
{% for href, id, caption in navigation_bar %}
  <li{% if id == active_page %} class="active"{% endif
  %}><a href="{{ href|e }}">{{ caption|e }}</a>/li>
{% endfor %}
</ul>
...

Accessing the parent Loop

The special loop variable always points to the innermost loop. If it’s desired to have access to an outer loop it’s possible to alias it:

<table>
{% for row in table %}
  <tr>
  {% set rowloop = loop %}
  {% for cell in row %}
    <td id="cell-{{ rowloop.index }}-{{ loop.index }}>{{ cell }}</td>
  {% endfor %}
  </tr>
{% endfor %}
</table>