Skip to content

Instantly share code, notes, and snippets.

@kevin-brown
Last active May 20, 2024 20:19
Show Gist options
  • Save kevin-brown/ec945b60024d35ed9c09ec70142af7fe to your computer and use it in GitHub Desktop.
Save kevin-brown/ec945b60024d35ed9c09ec70142af7fe to your computer and use it in GitHub Desktop.
Examples of syntax for the Jinja templating language

for

Basic with list

<h1>Members</h1>
<ul>
{% for user in users %}
  <li>{{ user.username|e }}</li>
{% endfor %}
</ul>

Basic with dictionary

<dl>
{% for key, value in my_dict.items() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

loop.cycle()

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

For loop with conditional

{% for user in users if not user.hidden %}
    <li>{{ user.username|e }}</li>
{% endfor %}

For loop with else

<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% else %}
    <li><em>no users found</em></li>
{% endfor %}
</ul>

Recursive for loop

<ul class="sitemap">
{%- for item in sitemap recursive %}
    <li><a href="{{ item.href|e }}">{{ item.title }}</a>
    {%- if item.children -%}
        <ul class="submenu">{{ loop(item.children) }}</ul>
    {%- endif %}</li>
{%- endfor %}
</ul>

loop.previtem and loop.nextitem

{% for value in values %}
    {% if loop.previtem is defined and value > loop.previtem %}
        The value just increased!
    {% endif %}
    {{ value }}
    {% if loop.nextitem is defined and loop.nextitem > value %}
        The value will increase even more!
    {% endif %}
{% endfor %}

loop.changed()

{% for entry in entries %}
    {% if loop.changed(entry.category) %}
        <h2>{{ entry.category }}</h2>
    {% endif %}
    <p>{{ entry.message }}</p>
{% endfor %}

if

Basic usage

{% if users %}
<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}

elif and else

{% if kenny.sick %}
    Kenny is sick.
{% elif kenny.dead %}
    You killed Kenny!  You bastard!!!
{% else %}
    Kenny looks okay --- so far
{% endif %}

macro

{% macro input(name, value='', type='text', size=20) -%}
    <input type="{{ type }}" name="{{ name }}" value="{{
        value|e }}" size="{{ size }}">
{%- endmacro %}
{% macro input(name, value='', type='text') -%}
    <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
{%- endmacro %}
{%- macro textarea(name, value='', rows=10, cols=40) -%}
    <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols
        }}">{{ value|e }}</textarea>
{%- endmacro %}

call

{% macro render_dialog(title, class='dialog') -%}
    <div class="{{ class }}">
        <h2>{{ title }}</h2>
        <div class="contents">
            {{ caller() }}
        </div>
    </div>
{%- endmacro %}

{% call render_dialog('Hello World') %}
    This is a simple dialog rendered by using a macro and
    a call block.
{% endcall %}

Returning values

{% macro dump_users(users) -%}
    <ul>
    {%- for user in users %}
        <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
    {%- endfor %}
    </ul>
{%- endmacro %}

{% call(user) dump_users(list_of_user) %}
    <dl>
        <dt>Realname</dt>
        <dd>{{ user.realname|e }}</dd>
        <dt>Description</dt>
        <dd>{{ user.description }}</dd>
    </dl>
{% endcall %}

filter

Basic

{% filter upper %}
    This text becomes uppercase
{% endfilter %}

Arguments

{% filter center(100) %}Center this{% endfilter %}

set

Single assignment

{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}

Multiple assignment

{% set key, value = call_something() %}

Namespaces

{% set ns = namespace(found=false) %}
{% for item in items %}
    {% if item.check_something() %}
        {% set ns.found = true %}
    {% endif %}
    * {{ item.title }}
{% endfor %}
Found item having something: {{ ns.found }}

Block assignment

{% set navigation %}
    <li><a href="/">Index</a>
    <li><a href="/downloads">Downloads</a>
{% endset %}

Block assignment with filters

{% set reply | wordwrap %}
    You wrote:
    {{ message }}
{% endset %}

include

Basic

{% include 'header.html' %}
Body goes here.
{% include 'footer.html' %}

With context

{% include "sidebar.html" without context %}

Ignore missing

{% include "sidebar.html" ignore missing %}

Ignore missing with context

{% include "sidebar.html" ignore missing with context %}

Ignore missing without context

{% include "sidebar.html" ignore missing without context %}

List of templates

{% include ['page_detailed.html', 'page.html'] %}

List of templates ignore missing

{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}

Template as a variable

{% include template_name %}

import / from

Basic as

{% import 'forms.html' as forms %}

From import

{% from 'forms.html' import input as input_field, textarea %}

From import with context

{% from 'forms.html' import input with context %}

block

<!DOCTYPE html>
<html lang="en">
<head>
    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
</head>
<body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
        &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.
        {% endblock %}
    </div>
</body>
</html>

Super usage

{% block sidebar %}
    <h3>Table Of Contents</h3>
    ...
    {{ super() }}
{% endblock %}

Super super usage

{% block body %}Hi from grandchild2. {{ super.super() }} {% endblock %}

Named block end tags

{% block sidebar %}
    {% block inner_sidebar %}
        ...
    {% endblock inner_sidebar %}
{% endblock sidebar %}

Scoped block nesting

{% for item in seq %}
    <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}

Required blocks

{% block body required %}{% endblock %}

Scoped required blocks

{% block body scoped %}{% endblock %}
{% block body required %}{% endblock %}
{% block body scoped required %}{% endblock %}

extends

{% extends "base.html" %}

Literals

Strings

"Hello World"

Integers

42

Integers with underscores

123_456

Floats

42.23

Floats with exponential notation

42.1e2

Floats with underscores

123_456.789

List

['list', 'of', 'objects']

Tuple

('tuple', 'of', 'values')

Dictionary

{'dict': 'of', 'key': 'and', 'value': 'pairs'}

Constants

true
false
none

Math

Addition

{{ 1 + 1 }}

Subtraction

{{ 3 - 2 }}

Division

{{ 1 / 2 }}

Integer division

{{ 20 // 7 }}

Modulo divison

{{ 11 % 7 }}

Multiplication

{ 2 * 2 }}
{{ '=' * 80 }}

Power

{{ 2**3 }}
{{ 3**3**3 }}

Comparisons

Equals

a == b

Not equals

Greater than

a > b

Greater than or equal

a >= b

Less than

a < b

Less than or equal

a <= b

Logic

And

a and b

Or

a or b

Not

not a

Parentheses

a and (b or c)

Other operators

In

{{ 1 in [1, 2, 3] }}
{{ 1 not in [2, 3] }}

Concatenation

{{ "Hello " ~ name ~ "!" }}

If expressions

{% extends layout_template if layout_template is defined else 'default.html' %}
{{ "[{}]".format(page.title) if page.title }}

abs

foo|abs

attr

foo|attr("bar")

batch

<table>
{%- for row in items|batch(3, '&nbsp;') %}
  <tr>
  {%- for column in row %}
    <td>{{ column }}</td>
  {%- endfor %}
  </tr>
{%- endfor %}
</table>

capitalize

foo|capitalize

center

foo|center
foo|center(20)

default

Default if not defined

{{ my_variable|default('my_variable is not defined') }}

Default if false

{{ ''|default('the string was empty', true) }}

dictsort

Sort the dict by key, case insensitive

{% for key, value in mydict|dictsort %}
    sort the dict by key, case insensitive
{% endfor %}

Sort the dict by key, case insensitive, reverse order

{% for key, value in mydict|dictsort(reverse=true) %}
    sort the dict by key, case insensitive, reverse order
{% endfor %}

Sort the dict by key, case sensitive

{% for key, value in mydict|dictsort(true) %}
    sort the dict by key, case sensitive
{% endfor %}

Sort the dict by value, case insensitive

{% for key, value in mydict|dictsort(false, 'value') %}
    sort the dict by value, case insensitive
{% endfor %}

escape

foo|escape

filesizeformat

Decimal prefixes

foo|filesizeformat

Binary prefixes

foo|filesizeformat(false)

first

foo|first

float

No default

foo|float

With default

foo|float(1.0)

forceescape

foo|forceescape

format

{{ "%s, %s!"|format(greeting, name) }}
Hello, World!

groupby

Attribute retrieval with unpacking

<ul>{% for city, items in users|groupby("city") %}
  <li>{{ city }}
    <ul>{% for user in items %}
      <li>{{ user.name }}
    {% endfor %}</ul>
  </li>
{% endfor %}</ul>

Without unpacking

<ul>{% for group in users|groupby("city") %}
  <li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>

Default for missing attribute

<ul>{% for city, items in users|groupby("city", default="NY") %}
  <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
{% endfor %}</ul>

Case insensitive grouping

<ul>{% for group in users|groupby("city", case_sensitive=True) %}
  <li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>

indent

Default indent 4

foo|indent

Indent the first line as well

foo|indent(first=True)

Indent blank lines as well

foo|indent(blank=True)

int

Standard usage

foo|int

Default if failed to convert

foo|int(100)

Base for conversion

foo|int(base=2)

items

<dl>
{% for key, value in my_dict|items %}
    <dt>{{ key }}
    <dd>{{ value }}
{% endfor %}
</dl>

join

Implicit join with no separator

{{ [1, 2, 3]|join }}

Join separator

{{ [1, 2, 3]|join('|')

Join attributes

{{ users|join(', ', attribute='username') }}

last

{{ data | selectattr('name', '==', 'Jinja') | list | last }}

length

foo|length
foo|count

list

foo|list

lower

foo|lower

map

Attribute lookup

Users on this page: {{ users|map(attribute='username')|join(', ') }}

Attribute with default

{{ users|map(attribute="username", default="Anonymous")|join(", ") }}

Mapping function

Users on this page: {{ titles|map('lower')|join(', ') }}

max / min

Default usage

[1, 2, 3]|min

Case sensitive

['a', 'A', 'b', 'B']|min(case_sensitive=False)

Attribute comparison

foo|min(attribute="bar")

pprint

foo|pprint

random

[1, 2, 3]|random

reject

Reject as boolean

{{ [True, False, True]|reject }}

Reject with a test

{{ numbers|reject("odd") }}

rejectattr

Boolean on atttribute

{{ users|rejectattr("is_active") }}

Test applied to attribute

{{ users|rejectattr("email", "none") }}

replace

Standard find and replace

{{ "Hello World"|replace("Hello", "Goodbye") }}

Only replace a certain number of occurrences

{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}

reverse

[1, 2, 3]|reverse

round

Default common integrer rounding

{{ 42.55|round }}

Specify the rounding precision

{{ 42.55|round(1) }}

Specify the rounding method

{{ 42.55|round(1, 'floor') }}

safe

foo|safe

select

Selecting by truthiness

{{ [True, False, True]|select }}

Calling a standard test

{{ numbers|select("odd") }}

Calling a test with a parameter

{{ numbers|select("divisibleby", 3) }}
{{ numbers|select("lessthan", 42) }}
{{ strings|select("equalto", "mystring") }}

selectattr

Boolean on atttribute

{{ users|selectattr("is_active") }}

Test applied to attribute

{{ users|selectattr("email", "none") }}

slice

Slicing specific number

<div class="columnwrapper">
  {%- for column in items|slice(3) %}
    <ul class="column-{{ loop.index }}">
    {%- for item in column %}
      <li>{{ item }}</li>
    {%- endfor %}
    </ul>
  {%- endfor %}
</div>

Filling missing slices

<div class="columnwrapper">
  {%- for column in items|slice(3, 'TBD') %}
    <ul class="column-{{ loop.index }}">
    {%- for item in column %}
      <li>{{ item }}</li>
    {%- endfor %}
    </ul>
  {%- endfor %}
</div>

sort

Built-in sorted

{% for city in cities|sort %}
    ...
{% endfor %}

Reverse sorting

{% for user in users|sort(attribute="name")
    |sort(reverse=true, attribute="age") %}
    ...
{% endfor %}

Sorting by attribute

{% for user in users|sort(attribute="age,name") %}
    ...
{% endfor %}

string

foo|string

striptags

foo|striptags

sum

Standard sum

Total: {{ items|sum }}

Starting value

([1,2],[3,4])|sort(start=[])

Sum by attribute

Total: {{ items|sum(attribute='price') }}

title

foo|title

tojson

Compressed JSON

foo|tojson

Indenting a certain number

foo|tojson(4)

trim

Trim whitespace

foo|trim

Trim specific characters

foo|trim('abc')

truncate

Truncate after a certain number of characters

{{ "foo bar baz qux"|truncate(9) }}
{{ "foo bar baz qux"|truncate(11) }}

Specify if truncating in the middle of a word is allowed

{{ "foo bar baz qux"|truncate(9, True) }}

Specify a custom string to use for the ellipsis sign

{{ "foo bar baz qux"|truncate(9, False, '---') }}

Specify the amount of leeway when truncating

{{ "foo bar baz qux"|truncate(11, leeway=0) }}

unique

{{ ['foo', 'bar', 'foobar', 'FooBar']|unique }}
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique(case_sensitive=True) }}
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique(attribute='upper', case_sensitive=True) }}

upper

foo|upper

urlencode

foo|urlencode

urlize

foo|urlize
foo|urlize(trim_url_limit=50)
foo|urlize(nofollow=True)
foo|urlize(target='_blank')
foo|urlize(rel='nofollow')
foo|urlize(extra_schemes=['mock'])

wordcount

foo|wordcount

wordwrap

foo|wordwrap(120)
foo|wordwrap(break_long_words=True)
foo|wordwrap(break_on_hyphens=True)
foo|wordwrap(wrapstring='<br />')

xmlattr

<ul{{ {'class': 'my_list', 'missing': none,
        'id': 'list-%d'|format(variable)}|xmlattr }}>
...
</ul>

range

lipsum

dict

cycler

current

next

reset

joiner

namespace

Default kwargs

boolean

callable

defined

divisibleby

eq

escaped

even

false

filter

float

ge

gt

in

integer

iterable

le

lower

lt

mapping

ne

none

number

odd

sameas

sequence

string

test

true

undefined

upper

Call a callable

Attribute retrieval

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment