2023-03-10

Jinja Templating Engine in Python

What is Jinja

Jinja is a popular templating engine for Python, widely used for generating dynamic web pages, HTML, XML and other markup languages.

It is inspired by Django's templating system, and provides a fast and efficient way to separate the presentation layer from the business logic layer of your web application. With its powerful features such as template inheritance, macros, filters, and loop control, Jinja allows developers to create complex and dynamic templates with ease.

How to Use Jinja

Setting up Jinja in Python is a simple process that involves installing the Jinja package and creating a template file. Here's an example of how to set up Jinja in Python:

  1. Install Jinja package using pip
bash
$ pip install jinja2
  1. Create a template file named template.html with the following contents
template.html
<!DOCTYPE html>
<html>
<head>
	<title>{{ title }}</title>
</head>
<body>
	<h1>{{ heading }}</h1>
	<ul>
	{% for item in items %}
		<li>{{ item }}</li>
	{% endfor %}
	</ul>
</body>
</html>
  1. In your Python script, import the jinja2 module and load the template file
python
from jinja2 import Template, FileSystemLoader, Environment

env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('template.html')
  1. Define the variables to be used in the template
python
title = 'My Template'
heading = 'Welcome to my template'
items = ['item 1', 'item 2', 'item 3']
  1. Render the template with the defined variables
python
output = template.render(title=title, heading=heading, items=items)
print(output)

This will output the rendered HTML code with the defined variables inserted into the template. You can also write the output to a file or pass it to a web framework to display on a webpage.

<!DOCTYPE html>
<html>
  <head>
    <title>My Template</title>
  </head>
  <body>
    <h1>Welcome to my template</h1>
    <ul>
      <li>item 1</li>
      <li>item 2</li>
      <li>item 3</li>
    </ul>
  </body>
</html>

Jinja Syntax

One of the key benefits of Jinja is its easy-to-use syntax, which allows you to create templates that are easy to read and understand.

Variables

One of the most common features in Jinja is the ability to insert dynamic data into a template using variables. Variables are defined using double curly braces {{ variable_name }}. For example, if you have a variable called name with the value John, you can insert it into a template like this:

html
<p>My name is {{ name }}.</p>

Loops

Another powerful feature of Jinja is the ability to loop over data structures like lists and dictionaries. This is useful when you need to generate repetitive markup or iterate over data. The syntax for a loop is {% for item in list %} ... {% endfor %}. For example, if you have a list of names, you can loop over it like this:

html
<ul>
  {% for name in names %}
    <li>{{ name }}</li>
  {% endfor %}
</ul>

Loop Specific Variables

In Jinja, loops allow you to iterate over a collection of items and perform an action on each item. While iterating, Jinja provides specific variables that give you more control over the loop and enable you to access specific information about the iteration. Here are the list of loop-specific variables in Jinja:

Variable Description
loop.index This variable represents the current iteration index, starting from 1.
loop.index0 This variable represents the current iteration index, starting from 0.
loop.revindex This variable represents the number of iterations from the end, starting from 1.
loop.revindex0 This variable represents the number of iterations from the end, starting from 0.
loop.first This variable is a boolean that is True on the first iteration and False otherwise.
loop.last This variable is a boolean that is True on the last iteration and False otherwise.
loop.length This variable represents the total number of iterations.

Here is an example that demonstrates the use of these variables in Jinja:

html
<ul>
{% for item in items %}
    <li>{{ loop.index }}. {{ item }}</li>
{% endfor %}
</ul>

In this example, we're iterating over a collection of items and displaying each item in an unordered list (<ul>). We're using the loop.index variable to display the iteration index along with each item.

Jinja also allows you to iterate over lists of dictionaries using the dictsort filter. Here's an example that demonstrates this:

html
<ul>
{% for item in items|dictsort(attribute='name') %}
    <li>{{ item.name }} ({{ item.price }})</li>
{% endfor %}
</ul>

In this example, we're iterating over a list of dictionaries that contain name and price keys. We're using the dictsort filter to sort the list by the name attribute before iterating over it. Inside the loop, we're using the item.name and item.price syntax to access the values of each dictionary.

Conditions

Jinja also supports conditional statements, which allow you to show or hide markup based on certain conditions. The syntax for a conditional statement is {% if condition %} ... {% endif %}. For example, if you have a variable called is_logged_in that indicates whether a user is logged in or not, you can show different content based on its value:

html
{% if is_logged_in %}
  <p>Welcome back!</p>
{% else %}
  <p>Please log in to continue.</p>
{% endif %}

Advanced Jinja Features

In addition to its basic syntax features, Jinja also offers advanced features such as macros and template inheritance that can further enhance the flexibility and efficiency of your templates.

Macros

One of its advanced features is the ability to define reusable code snippets, known as macros. Macros are similar to functions in programming languages, and they allow you to simplify and organize your templates by encapsulating commonly used code.

To define a macro in Jinja, you can use the {% macro %} tag. Here's an example:

{% macro greeting(name) %}
    Hello, {{ name }}!
{% endmacro %}

This macro is named greeting and accepts one argument, name. It returns a simple greeting message using the {{ name }} syntax to output the value of the name variable.

To use the greeting macro in your template, you can call it with the {% call %} tag, like this:

{% call greeting('Alice') %}
{% endcall %}

This will render the following output:

Hello, Alice!

You can also pass a variable to the macro, like this:

{% set my_name = 'Bob' %}
{% call greeting(my_name) %}
{% endcall %}

This will render the following output:

Hello, Bob!

By defining macros in Jinja, you can avoid repeating the same code across your templates, making them more modular and easier to maintain.

Template Inheritance

Template inheritance is a powerful feature in Jinja that allows you to reuse common elements of a template across multiple pages. With template inheritance, you can define a base template that contains the common elements of your site, such as the header, footer, and navigation menu. You can then create child templates that inherit from the base template and add their own content.

To define a base template in Jinja, you need to use the {% block %} tag to define blocks of content that can be overridden by child templates. Here's an example of a simple base template:

html
<!DOCTYPE html>
<html>
  <head>
    <title>{% block title %}Default Title{% endblock %}</title>
  </head>
  <body>
    <header>
      {% block header %}
      <nav>
        <ul>
          <li><a href="#">Home</a></li>
          <li><a href="#">About</a></li>
          <li><a href="#">Contact</a></li>
        </ul>
      </nav>
      {% endblock %}
    </header>
    <main>
      {% block content %}{% endblock %}
    </main>
    <footer>
      {% block footer %}
      &copy; 2023 My Site
      {% endblock %}
    </footer>
  </body>
</html>

In this example, the {% block %} tags define three blocks of content: title, header, and footer. The content of these blocks can be overridden by child templates.

To create a child template that inherits from the base template, you need to use the {% extends %} tag to specify the name of the base template, and then use the {% block %} tags to override the content of the blocks. Here's an example of a child template that overrides the title and content blocks:

html
{% extends "base.html" %}

{% block title %}My Page Title{% endblock %}

{% block content %}
<h1>Welcome to my page!</h1>
<p>This is some content for my page.</p>
{% endblock %}

In this example, the {% extends %} tag specifies that the child template should inherit from the base.html template. The {% block %} tags then override the title and content blocks defined in the base template.

When you render the child template, Jinja will automatically use the base template as a starting point and insert the content of the overridden blocks. The resulting HTML will contain the common elements of the site defined in the base template, as well as the specific content of the child template.

SQL with Jinja

The followings are examples of writing SQL with using Jinja.

INSERT

Here's an example of how to use Jinja to generate SQL insert statements with arbitrary numbers of rows and columns in Python:

python
import jinja2

# define your data
data = [
    ['Alice', 25, 'Female'],
    ['Bob', 30, 'Male'],
    ['Charlie', 40, 'Male'],
]

# define the template
template = """
INSERT INTO my_table (name, age, gender)
VALUES
{% for row in data %}
    (
    {% for col in row %}
        {% if col is string %}
        '{{ col }}' {% if not loop.last %},{% endif %}
        {% else %}
        {{ col }} {% if not loop.last %},{% endif %}
        {% endif %}
    {% endfor %}
    ) {% if not loop.last %},{% endif %}
{% endfor %}
"""

# compile the template
template = jinja2.Template(template)

# render the SQL statement with the data
sql_statement = template.render(data=data)

print(sql_statement)

In this example, we first define our data as a list of lists. Each inner list represents a row of data to be inserted into the table.

We then define the SQL insert statement as a Jinja template. We use a for loop to iterate over each row in the data list, and another for loop to iterate over each column in the row. We use the loop.last variable to add commas only between columns, but not after the last column in each row or the last row in the data.

We also use a conditional statement to check if the current column value is a string or not. If it is a string, we enclose it in quotes before inserting it into the SQL statement.

Finally, we compile the Jinja template and render the SQL statement with the data using the render method. The resulting SQL statement can then be executed against the database.

UPDATE

Here's an example code for updating an SQL table using Jinja and Python:

python
import jinja2

# Define the data for the update
update_data = {
    'column1': 'new_value1',
    'column2': 'new_value2',
    'column3': 'new_value3'
}

# Define the Jinja template for the update query
update_query_template = """
    UPDATE my_table
    SET {% for column, value in update_data.items() %}
        {{ column }} = {{ value }}{% if not loop.last %},{% endif %}
    {% endfor %}
    WHERE id = {{ id }};
"""

# Create the Jinja environment and render the query template
env = jinja2.Environment()
update_query = env.from_string(update_query_template).render(update_data=update_data, id=123)

In this code, we first define the data we want to use for the update, which is a dictionary of column names and their new values.

Then we define a Jinja template for the update query. Inside the template, we use a for loop to iterate over the column names and values in the update_data dictionary, and set each column to its corresponding new value. We use the loop.last variable to check if we're on the last iteration of the loop, and add a comma if we're not, to ensure the SQL syntax is correct.

Finally, we create a Jinja environment, render the query template with the update_data dictionary and the ID of the row we want to update, and execute the resulting query using our database connector.

References

https://jinja.palletsprojects.com/en/3.1.x/

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!