Jamming with Jinja2 Template Engine

AMIT RAWAT
5 min readJul 28, 2023

Some Context:

I recently got a chance to build a static website to host the product requirements where the ask was to convert the requirements data from yaml files to HTML so that later these HTML files can be hosted on some static website.

I was looking for a templating engine that provides the following features:

  • Powerful Syntax: To provide features like macros, loops, conditionals, and filters
  • Template Inheritance: support for template inheritance, allowing us to create modular and reusable templates.
  • Extensibility: To provide a robust extension system, allowing you to create custom filters, tags, and global functions.
  • Security: With a strong focus on security, with built-in features like auto-escaping to prevent common web vulnerabilities such as cross-site scripting (XSS) attacks.

Jinja2 qualifies all the above requirements and hence I decided to go with it.

Introduction:

Jinja2 is a powerful and widely used template engine for Python that allows developers to generate dynamic content, such as HTML, XML, or any other text-based format.

In this blog post, we will explore the capabilities of Jinja2 and how it can be used with Python and Java to create HTML files. We will also delve into how data can be fed from YAML files to generate dynamic content efficiently.

What is Jinja2 Template Engine?

Jinja2 is a popular and feature-rich template engine for Python, inspired by the Django template engine. It provides a way to separate the presentation layer from the logic of your application. With Jinja2, you can define templates containing placeholders that are later filled with dynamic data. These templates can be reused, making it easier to maintain and update your code.

Jinja is not only a city in the Eastern Region of Uganda and a Japanese temple, but also a template engine. You commonly use template engines for web templates that receive dynamic content from the back end and render it as a static page in the front end.

Let’s explore some cool features of the Jinja2 template engine:

Template inheritance

We can easily refer to the base template from any child template as shown here:

Base template (base.html):

<!DOCTYPE html>
<html>
<head>
<title>{% This is my title %}Default Title{% endblock %}</title>
</head>
<body>
<div class="content">
{% bsome content %}{% endblock %}
</div>
</body>
</html>

Child template (child.html) extending the base template:

{% extends "base.html" %}

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

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

Statements and Expressions:

We can use expressions like if-else, for loops, etc.

<p>{{ "Welcome, " + name + "!" }}</p>

{% if age >= 18 %}
<p>You are an adult.</p>
{% else %}
<p>You are a minor.</p>
{% endif %}

<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>

Filters:

This one is my favourite feature and it stands out compared to other template engines.

Jinja2 provides a rich set of filters that can be applied to variables within templates. Filters allow you to modify and format data before rendering it, providing more flexibility and control over the output. Let’s explore some commonly used Jinja2 filters:

Default Filter:

The default filter is useful when you want to provide a fallback value if a variable is not defined or is empty. It can be used as follows:

{{ variable_name | default('Fallback Value') }}

Some other common filters are : upper , lower , length , join, format etc.

You can see the usage of these filters here:

{{ variable_name | upper }}
{{ variable_name | lower }}

{{ variable_name | length }}

{{ list_name | join(', ') }}

Macros:

Macro allows you to define a reusable block:

{% macro say_hello(name) %}
<p>Welcome, {{ name }}!</p>
{% endmacro %}

{{ say_hello("Amit") }}
{{ say_hello("John") }}

Using Jinja2 with Python

Jinja2 can be seamlessly integrated into Python applications, allowing you to generate dynamic content effortlessly. Here’s a step-by-step guide on how to use Jinja2 with Python:

  1. Install Jinja2: Begin by installing Jinja2 using pip, the package installer for Python. Open your terminal or command prompt and run the following command:
pip install Jinja2

2. Set up the Template: Create a Jinja2 template file with a .html extension. Within this template, you can define placeholders enclosed in double curly braces ({{ variable_name }}). These placeholders will be replaced with actual data during rendering.

3. Load the Template: In your Python code, import the necessary modules and load the Jinja2 template using the Environment class. Here's an example:

from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('path/to/templates'))
template = env.get_template('template_name.html')

data = {
'name': 'John Doe',
'age': 25,
# Additional data
}

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

Integrating Jinja2 with Java

Thanks to HubSpot for building this cool extension of this template engine in Java, which is called Jinjava.

We just need to define this maven dependency:

  <dependency>
<groupId>com.hubspot.jinjava</groupId>
<artifactId>jinjava</artifactId>
<version>{ LATEST_VERSION }</version>
</dependency>

And now we can render the same HTML in Java which we consumed using the above python code.

Jinjava jinjava = new Jinjava();
Map<String, Object> context = Maps.newHashMap();
context.put("name", "John Doe");

String template = Resources.toString(Resources.getResource("template_name.html"), Charsets.UTF_8);

String renderedTemplate = jinjava.render(template, context);

Using this Jinjava we can also do some advance things like:

Defining your own custom filters:

Let's say we want to define our own custom`ConcatFilter` to concatenate two strings. This can be done as shown below:

public class ConcatFilter implements Filter {
@Override
public String getName() { return "concat"; }

@Override
public Object filter(Object var,
JinjavaInterpreter interpreter,
String... args)
{
String addend = args[0];
return var.toString() + addend;
}
}

To register this new filter with the template engine:

Jinjava jinjava = new Jinjava();
jinjava.getGlobalContext().registerFilter(new ConcatFilter());

We can also integrate Jinja2 with Ansible playbook and more details can be found here.

Now if you are in dilemma that which language python or java should be used for the implementation engine. The answer is that you can use any as per your comfort but in case you are looking for better performance then Jinajava is much superior compared to Jinja2(Python).

Here is the performance comparison and we can see Jinjava is slightly faster. This data is collected from here.

Conclusion:

Jinja2 is a versatile template engine that empowers developers to generate dynamic content efficiently. By integrating Jinja2 with Python, Ansible, and Jinjava, you can create powerful applications and easily generate dynamic HTML files. Leveraging YAML files as a data source further enhances the flexibility and maintainability of your code. Start jamming with Jinja2 and unlock the potential for dynamic content generation in your projects.

--

--

AMIT RAWAT

I am a Civil Engineer by qualification, an Engineering Manager by profession and a Developer by passion. (amitrawat.dev)