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:
- Install Jinja package using pip
$ pip install jinja2
- Create a template file named template.html with the following contents
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ heading }}</h1>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
- In your Python script, import the
jinja2
module and load the template file
from jinja2 import Template, FileSystemLoader, Environment
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('template.html')
- Define the variables to be used in the template
title = 'My Template'
heading = 'Welcome to my template'
items = ['item 1', 'item 2', 'item 3']
- Render the template with the defined variables
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:
<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:
<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:
<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:
<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:
{% 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:
<!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 %}
© 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:
{% 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:
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:
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