Jinja2
External
- https://jinja.palletsprojects.com/en/latest/
- https://medium.com/knoldus/jinja2-template-the-modern-design-friendly-templating-engine-a9218fec96e5
- https://pypi.org/project/Jinja2/
Internal
Overview
Jinja2 is a templating engine. Placeholders in the template allow writing code that has a syntax similar to Python. The engine ingests the template and data and renders the final document.
Jinja2 provides template inheritance and inclusion.
Jinja2 allows definition and import of macros within the template.
Templated are compiled to Python code and cached, or they can be compiled ahead of time.
Jinja2 provides extensible filters, tests, functions and syntax.
Playground
Programming Model
Find out what the latest version is from https://pypi.org/project/Jinja2/
Then add this to your requirements.txt
jinja2 == 3.0.3
Once the virtual environment is updated, use it as such:
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
template_dir = Path('...')
text = Environment(loader=FileSystemLoader(template_dir))\
.get_template('my-template.yaml.j2') \
.render(variable_1='some value', variable_2='some other value')
If the content is already loaded:
template_as_text = '...'
rtemplate = Environment().from_string(template_as_text)
data = rtemplate.render(variable_1='some value', variable_2='some other value')
Variables
Variables can be provided individually as arguments of the render()
method.
Alternatively, a recursive data structure can be provided as argument.
Templating Language
Variable
raw content followed by {{ variable1 }}
Conditional
{%if some_var == "something" -%}
something
something else {{ var_1 }}
{% elif some_var == "something else" -%}
something else
{% else %}
something completely different {{ var_2 }}
{%- endif %}
This works with empty strings too:
{%if some_var != "" -%}
my var is {{ some_var }}
defined Conditional
To check whether a variable is defined or not defined:
{%if some_var is defined -%}
something
{%- endif %}
{%if some_var is not defined -%}
something else
{%- endif %}
Check whether a Value is None
Note that a variable that has a None
value is still defined, so the above is defined
test will pass.
To check for None
, specifically:
{%if none(some_var) -%}
'som_var' is None
{%- endif %}
The following construct broke the renderer when some_var
was None
:
{%if some_var is some_var and not none(some_var) -%}
{{ queues }}
{%- endif %}
Error message:
> ??? E TypeError: 'NoneType' object is not callable
Specific Boolean Values
To check for a specific boolean value:
{%if some_var == false -%}
something
{%- endif %}
Type Conditional
To check whether a value is a string:
{%if some_var is string -%}
something
{%- endif %}
For more built-in filters and tests:
Conditional Expressions
{%if some_var == "a" and some_other_var == "b" -%}
my vars are {{ some_var }}, {{ some_other_var }}
Loops
my_list:
{%- for i in seq %}
- '{{ i }}'
{%- endfor %}
where seq
is a Python list:
seq = ['a', 'b']
text = Environment(loader=FileSystemLoader(template_dir)).get_template('my-template.yaml.j2').render(seq=seq)
Rendering Dictionaries
from jinja2 import Environment
template_as_text = '''
something:
{%- for key, value in a_dict.items() %}
{{key}}: {{value-}}
{% endfor %}
somethingelse
'''
a_dict = {'a': 'A', 'b': 'B', 'c': 'C'}
rtemplate = Environment().from_string(template_as_text)
data = rtemplate.render(a_dict=a_dict)
print(data)
This will render:
something:
a: A
b: B
c: C
somethingelse
Rendering a List of Dictionaries
{% if a_list_of_maps %}
some_tag_that_introduces_the_list_of_maps:
{% for m in a_list_of_maps %}
-
{% for k, v in m.items() %}
{{ k }}: {{ v }}
{% endfor %}
{%- endfor %}
{%- endif %}
Rendering Embedded Maps
If a complex recursive data structure, such as embedded maps, is passed to render()
, an arbitrary level key can be accessed with the dot notation and also by key:
m = {
'm1': {
'color': 'red'
},
'm2': {
'color': 'blue'
}
}
template_as_text = '''
color1: {{ m.m1.color }}
color2: {{ m['m2']['color'] }}
'''
rtemplate = Environment().from_string(template_as_text)
data = rtemplate.render(m=m)
print(data)
will print:
color1: red
color2: blue
Rendering an Object's __str__() Representation
The __str__()
is honored, but if it is a multi-line string, only the first line is correctly indented.
Whitespace Management
A leading dash removes all whitespace (including new lines) between the last non space template character and it. A trailing dash removes all whitespace (including new lines) between it and the next non-whitespace character from the template.
{{-
-}}
{%-
-%}
Indentation
some_tag:
{{ rendered_multiline_configuration | indent(4) }}
The first line must be explicitly indented with the same number of space. The spaces are added after each new line.
Filters
TODO
What happens if a document containing a variable is rendered and the variable value is not provided?