A template engine for people who enjoy the simpler things in life.

Version 3.2.0

Template Markup

There are three kinds of template markup: comment tags, print tags, and instruction tags. Comment tags are the simplest kind; they look like this:

{# This is a comment. #}

Comments can span multiple lines and can be used to comment-out sections of template code.

Print tags evaluate and print expressions. They look like this:

{{ post.title }}

Print tags come in two flavours: regular and escaped. Escaped print tags escape HTML syntax characters in their output before printing it. They look like this:

{$ post.title $}

Escaped print tags are simply a shortcut for applying the built-in escape filter to their content. The example above is equivalent to:

{{ post.title|escape }}

Print tags can make use of two other constructs. First, print tags can contain multiple expressions separated by ||, the logical-OR operator. The first expression to evaluate as 'truthy' will be printed:

{{ post.meta_title || post.title || "Missing Title" }}

Second, print tags can make use of a C-style ternary operator:

{{ is_homepage ?? site.title :: post.title }}

If the test expression evaluates as 'truthy', the value of the first expression will be printed, otherwise the value of the second expression will be printed.

Note that a single print statement can make use of || chaining or the ternary construct, but not both.

Expressions and Filters

An expression consists of a variable name or a Python literal, optionally followed by a chain of pipe-separated filters.

Variables use dot-syntax to drill into nested objects or dictionaries:

{{ post.title }}

You can use integers to index into sequences like tuples or lists:

{{ posts.0.title }}

If the final variable in a chain evaluates to a function you can call it using brackets:

{{ post.get_title() }}

You can use simple Python literals like strings and integers as arguments to functions:

{{ call_me("ishmael", 42) }}

Filters are chainable functions that modify the value of an expression. You apply them using the pipe symbol:

{{ post.title|escape }}

Filters also accept arguments in brackets:

{{ post.content|striptags|truncatewords(50) }}

You can find a list of built-in filters here.

Note that expressions can use simple Python literals in place of variables:

{% if day|lower in ("saturday", "sunday") %}
    It's the weekend!
{% endif %}

The following literal structures can be used in expressions as arguments to callables or in place of variables: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

Instruction Tags

Instruction tags implement a broad range of behaviours like looping, conditional branching, and template inheritance. They look like this:

{% tag %}

Some instruction tags have block scope and require a closing tag. They look like this:

{% tag %} ... {% endtag %}

Tags with block scope can contain further template markup and can be nested to any depth.

You can find a list of built-in instruction tags here.

Differences from Django

Ibis's syntax is inspired by Django's but they aren't identical and templates written for Django are unlikely to work with Ibis.

In particular, Django's variable resolver automatically calls all variables that resolve to a function. Ibis never calls functions automatically — if you want to call a function you need to do so explicitly using brackets.

Also, you should note that Ibis only supports calling functions at the end of a variable chain — it doesn't support chaining function calls within an expression.