my cheat sheet python jinja2 templates

Home

Use C-c . hammer to update date

1 jinja2 overview

variables/parameters are recalled using double curlies {{}}

Twinkle, twinkle, litte {{stellar object}},
How I {{action}} what you are.
Up above the {{place}} so high,
Like a {{allegory}} in the sky

Jinja2 is originally built for python.

Jinja2 is a templating standard, where a document (template) can have variable substitution, {{ my_variable }}, and some amount of logic, {%%} for loops.

Jinja2 (often used with flask) is a python module that allows you to easily incorporate templates to allow your ansible routine to modify many different files, with unique fields

So, every color tag will look like: \[\033[COLORm\] where COLOR is: Black: 30 Red: 31 Green: 32 Yellow: 33 Blue: 34 Purple: 35 Cyan: 36 White: 37

Jinja2 can also be used direclty in an ansible playbook , i.e.

vars:
  my_file: "fixupfile"
debug: 
  msg: "My fixup file is {{ my_file }}"

2 Workflow (using python)

2.1 Working with .csv file for parameters in ansible

import csv

sourcefile = "vm_colours.csv"

with open(sourcefile) as f:
   reader = csv.DictReader(f)
   # DictReader lets us read the header values from the csv as well
   # as the usual data fields.
   # reader is an object type "OrderedDict"  type(reader) ===> "OrderedDict"
   for row in reader:
       print(row)  # while building code, good to scatter prints throughout

# run this in ipython to get a feel for what is in the .csv file
# then you can create a jinja2 template to read the data you need from it.

2.2 Sample jinja2 writing unique .bashprofile files

#!/usr/bin/env python
''' generate .bash_profile files unique to the guest vm

For ansible playbook. xxx.yml that will use the jinja2 ansible module.
In parallel, save each unique .bash_profile file as vm1.txt, vm2.txt, etc.

'''

import csv
from jinja2 import Template

colours_csv = "vm_colours.csv"
bash_template = "templates/bash_profile.j2"


with open(bash_template) as f:
    bash_profile_template = Template(f.read(), keep_trailing_newline=True)


with open(colours_csv) as f:
    reader = csv.DictReader(f)
    for row in reader:
        newprofile = bash_profile_template.render(
            c1 = row["User_colour"],
            c2 = row["Host_colour"],
            c3 = row["Dollar_colour"]
        )
        vm_profile = row["Guest_VM"] + ".txt"
        print(f' writing bash profile to local file: {vm_profile}')

        with open(vm_profile, "w") as g:
            g.write(newprofile)

print("\n\nDone.    Check out the new .txt files created in this directory\n")

3 Jinja2 filters

Examples should suffice:

"Province of employment : {{ work_prov | upper }}"  changes province to all uppercase
"Postal code : {{ addr_postalcode | lower }}"       changes to lower case.
"President was: {{ "Donald Trump" | replace ("Trump", "Drumpf") }}"  replaces a keyword
{{ [1, 2, 3] | min }}  returns 1
{{ [1, 2, 3] | max }}  returns 3
{{ [10] | random }}    returns a random number from 1 to 10

3.1 Loading jinja2 templates from a file using FileSystemLoader

from jinja2 import Environment, FileSystemLoader
file_loader = FileSystemLoader('templates')   # templates is a directory
env = Environment(loader=file_loader)
template = env.get_template('python_actors.j2')

output = template.render()
print(output)

Now, in the templates directory we can create a file called python_actors.j2

Hello Monty Python, including
John Cleese
Michael Palin
Terry Jones
Eric Idle
Terry Gilliam
Graham Chapman 

3.2 Using simple template variables from the above example

from jinja2 import Environment, FileSystemLoader
file_loader = FileSystemLoader('templates')   # templates is a directory
env = Environment(loader=file_loader)
template = env.get_template('python_actors.j2')

output = template.render(actorgroup='Cast of Holy Grail')
print(output)

Now, in the templates directory we can create a file called python_actors.j2

Hello {{actorgroup}}, including
John Cleese
Michael Palin
Terry Jones
Eric Idle
Terry Gilliam
Graham Chapman 

3.3 Using more complex template variables from the above example

This example is NOT good code, but meant more as a simplistic example of template variables. See the same result in a better way below using lists.

from jinja2 import Environment, FileSystemLoader
file_loader = FileSystemLoader('templates')   # templates is a directory
env = Environment(loader=file_loader)
template = env.get_template('python_actors.j2')

troup = {}   # a dictionary
troup['name'] = 'Monty Python'
troup['act1'] = 'John Cleese'
troup['act2'] = 'Michael Palin'
troup['act3'] = 'Terry Gilliam'
troup['act4'] = 'Terry Jones'
troup['act5'] = 'Eric Idle'
troup['act6'] = 'Graham Chapman'

output = template.render(actorgroup=troup)
print(output)

Now, in the templates directory we can create a file called python_actors.j2

Hello {{actorgroup.name}}, including
{{actorgroup.act1}}}
{{actorgroup.act2}}}
{{actorgroup.act3}}}
{{actorgroup.act4}}}
{{actorgroup.act5}}}
{{actorgroup.act6}}}

3.4 Control structures and for loops in complex templates

3.4.1 If statements

{% if truth %}
    This is true
{% else %}
    This is false
{% endif %}

Then the python code could be:

template = env.get_template('truth.txt')
output = template.render(truth=True)
print(output)

Will result in

This is true

3.4.2 for loops.

{% for colour in colours %}
  {{ colour }}
{% endfor %}

Then the corresponding python code to use this template is:

template = env.get_template('colours.j2')
colours = ['red', 'yellow', 'green', 'blue', 'purple', 'orange' ]

output = template.render(colours=colours)
print(output)

3.5 Better example of Monty Python example using lists

A better example of the Monty Python troup example from above.

from jinja2 import Environment, FileSystemLoader
file_loader = FileSystemLoader('templates')   # templates is a directory
env = Environment(loader=file_loader)
template = env.get_template('actor_list.j2')

troupname = 'Monty Python'
troup['John Cleese',
      'Michael Palin',
      'Terry Gilliam',
      'Terry Jones',
      'Eric Idle',
      'Graham Chapman']

output = template.render(troupname=troupname, troup = troup)
print(output)

Now, in the templates directory we can create a file called actor_list.j2

Hello {{troupname}}, including 
{% for thespian in troup %}
  {{ thespian }}
{% endfor %}

What a group of comedic geniuses!

4 jinja templates and flask

The other very common use of jinja templates is with Flask, and the jinja filters can come in very handy to sanitize html entered by hackers in your web pages.

4.1 Passing variables in jinja in flask.

There are two ways that are common way to pass variables to a jinja2 template when working with html flask templates. Python lets you pass any python object to a jinja template, i.e. string, £number, list, dictionary, object.

4.1.1 A. using <> in the url itself

If your flask page is defined like

@app.route('/recipe/<whattomake>')
def recipes(whattomake):
    return render_template("recipe.html", recipe=whattomake)

The template can then use the variable recipe in the jinja tags {{}}

<h2> Lets make {{recipe}}  Yummm!!! </h2>

And you would call that with

https://cooklikemomdid.ca/recipes/chocolatechipcookies 

which would then show a page like:

Lets make chocolatechipcookies   Yumm!!!

4.1.2 B. using straight python variables

The same example except using python variables vs url strings is: If your flask page is defined like this:

@app.route('/recipe/')
def recipes():
    whattomake = "chocolate chip cookies "
    return render_template("recipe.html", recipe=whattomake)

The template can then use the variable recipe in the jinja tags {{}}

<h2> Lets make {{recipe}}  Yummm!!! </h2>

And you would call that with

https://cooklikemomdid.ca/recipes/chocolatechipcookies 

which would then show a page like:

Lets make chocolatechipcookies   Yumm!!!

5 Jinja2 filters on variables

A very useful technique when using jinja with flask are the filters that one can use to sanitize user input from a web page. Whenever a web page lets users enter values in some html form, hackers often attempt to inject html code and java script code in these forms if you are not careful.

jinja2 filters can sanitize this junk. See below:

5.1 filter syntax

The filters are applied to the jinja variables in the html templates.

So rather than <h2> Lets make {{recipe}} </h2> you can say: <h2> Lets make {{recipe|filter}} </h2> where filter is one of the following: ~safe, capitalize, upper, lower, title, striptags, trim

You can also add multiple filters to the same variable i.e.

<h2> Lets make {{recipe|safe|lower}} </h2>= 

5.2 Filter examples

For the following

5.3 safe#+BEGINSRC html

somestring = "Please do <strong>not</strong> walk on the grass"
return render_template("pedestrian_signs.html",
                       grass_sign=somestring,
                       recipe=whattomake)

and in the pedestrainsigns.html jinja2 template:

<h2> Lets make  {{recipe}}  Yummm!!! </h2>
<h3> However,  {{grass_sign|safe|upper}}  </h3>

In an environment with automatic escaping enabled this variable will not be escaped. This safe filter tells you that I trust uses to pass html into this field, so the grass sign will have the word "not" bold and capitalized.

5.4 striptags

Does the opposite of ~safe ~ and removes all html tags from the passed variable.

somestring = "Please do <strong>not</strong> walk on the grass"
return render_template("pedestrian_signs.html",
                       grass_sign=somestring,
                       recipe=whattomake)

and in the pedestrainsigns.html jinja2 template:

<h2> Lets make  {{recipe}}  Yummm!!! </h2>
<h3> However,  {{grass_sign|striptags|upper}}  </h3>
  <h2> Lets make {{recipe|striptags}}  Yummm!!! </h2>

For strings, any html tags will be removed. Kind of the opp

5.5 first

<h2> Lets make {{recipe|first}}  Yummm!!! </h2>

If the variable is a list, will only take the first element of that list.

5.6 capitalize

<h2> Lets make {{recipe|capitalize}}  Yummm!!! </h2>

For strings, the first letter will be capitalized.

5.7 upper

<h2> Lets make {{recipe|upper}}  Yummm!!! </h2>

For strings, all the letters will be capitalized.

5.8 lower

<h2> Lets make {{recipe|lower}}  Yummm!!! </h2>

For strings, all the letters will be made lower case.

5.9 title

<h2> Lets make {{recipe|title}}  Yummm!!! </h2>

For strings, all the letters for each word will be capitalized.

5.10 trim

<h2> Lets make {{recipe|striptags}}  Yummm!!! </h2>

For strings, any leading or trailing whitespaces will be removed.

5.11 List of Filters online

For a list of available filters try: https://tedboy.github.io/jinja2/templ14.html

5.12 Home