# Jinja | ![img \|150](https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Jinja_software_logo.svg/320px-Jinja_software_logo.svg.png) | Jinja is a web template engine for the Python programming language. It was created by Armin Ronacher and is licensed under a BSD License. Jinja is similar to the Django template engine but provides Python-like expressions while ensuring that the templates are evaluated in a sandbox. It is a text-based template language and thus can be used to generate any markup as well as source code. | |-|-| | | wikipedia:: [Jinja (template engine)](https://en.wikipedia.org/wiki/Jinja_(template_engine)) | > [!summary]- Wikipedia Synopsis > Jinja is a web template engine for the Python programming language. It was created by Armin Ronacher and is licensed under a BSD License. Jinja is similar to the Django template engine but provides Python-like expressions while ensuring that the templates are evaluated in a sandbox. It is a text-based template language and thus can be used to generate any markup as well as source code. > > The **Jinja (template engine)** allows customization of tags, filters (for formatting or transforming values), tests (for evaluating conditions), and globals. Also, unlike the Django template engine, Jinja allows the template designer to call functions with arguments on objects. > > Jinja is Flask's default template engine and it is also used by Ansible, Trac, and Salt. It is also used to make SQL macros, for example for use with dbt. - http://jinja.pocoo.org/ - http://jinja.pocoo.org/docs/2.10/ - https://realpython.com/primer-on-jinja-templating/ - Default template for Flask and Pelican - Similar to Django templates - automatic HTML escaping - Templates evaluated in a sandbox - JIT compilcation with optional ahead of time compilation - General purpose - can be used for LaTeX, emails, CSS, XML, CSV, JavaScript, or configuration files. - Because html isn’t “white space aware”, you need to have the end statements in the templates for loops and conditionals, etc. - A Jinja template is simply a text file. - A Jinja template doesn’t need to have a specific extension: .html, .xml, or any other extension is just fine. - Writing Jinja Templates - http://jinja.pocoo.org/docs/2.10/templates/ - A template contains variables and/or expressions, which get replaced with values when a template is rendered; and tags, which control the logic of the template. The template syntax is heavily inspired by Django and Python. - can change the syntax configuration from `{% foo %}` to `<% foo %>`, or something similar. - Delimiters - Statements: {% … %} - Expressions: {{ … }} - Comments: {# … #} - Line Statements: \#  … ### - Template Extensions - Remember, you can use variables in base template as well. Ie, even if you pass data to an extended template, that data passes on up the inheritance chain to be inserted where it needs to be in whatever template, including the base template. - The extends tag can be used to extend one template from another. You can have multiple extends tags in a file, but only one of them may be executed at a time. - Blocks/Extension Points - Mark beginning and ending of block in base html file to be extended from: - {% block content %} {% endblock %} - Then use same syntax to mark where to extend that in a file that will inherit from the base: - But need to start it with on 1st line: {% extends “base.html” %} - {% block content %} {% endblock %} - You can specify the name after endblock for better readability if you want to: {% endblock content %} - You can’t define multiple {% block %} tags with the same name in the same template. The parent template wouldn’t know where to put the content. - But you can insert the same block multiple times: {{ self.title() }} for any additional blocks you want to use - Super Blocks - Block Nesting - Blocks can be nested for more complex layouts. - Block Nesting and Scope - per default blocks may not access variables from outer scopes: {% for item in seq %} ¶ `<li>`{=html} ¶ {% block loop_item %}{{ item }}{% endblock %} ¶ `</li>`{=html} ¶ {% endfor %} This example would output empty  ¶ `<li>`{=html} ¶  items because item is unavailable inside the block. The reason for this is that if the block is replaced by a child template, a variable would appear that was not defined in the block or passed to the context. Starting with Jinja 2.2, you can explicitly specify that variables are available in a block by setting the block to “scoped” by adding the scoped modifier to a block declaration: {% for item in seq %} ¶ `<li>`{=html} ¶ {% block loop_item scoped %}{{ item }}{% endblock %} ¶ `</li>`{=html} ¶ {% endfor %} When overriding a block, the scoped modifier does not have to be provided. - Variable Expressions - {{ variable }} - If the variable has not been passed, etc. it will render as ’‘, as opposed to needing to set the ’’ in str.format(), which is often useful because often that’s what you want. - the default behavior is to evaluate to an empty string if printed or iterated over, and to fail for every other operation. - Variable Attributes - You can use a dot (.) to access attributes of a variable in addition to the standard Python \_\_getitem\_\_ “subscript” syntax (\[\]). The following lines do the same thing: {{ foo.bar }} {{ foo\[’bar’\] }} - Implementation Details - For the sake of convenience, foo.bar in Jinja2 does the following things on the Python layer: -check for an attribute called bar on foo (getattr(foo, ’bar’)) -if there is not, check for an item ’bar’ in foo (foo.\_\_getitem\_\_(’bar’)) -if there is not, return an undefined object. foo\[’bar’\] works mostly the same with a small difference in sequence: -check for an item ’bar’ in foo. (foo.\_\_getitem\_\_(’bar’)) -if there is not, check for an attribute called bar on foo. (getattr(foo, ’bar’)) -if there is not, return an undefined object. This is important if an object has an item and attribute with the same name. Additionally, the attr() filter only looks up attributes. - Filters - For example, {{ name\|striptags\|title }} will remove all HTML Tags from variable name and title-case the output (title(striptags(name))). - Tests - can be used to test a variable against a common expression. - {% if loop.index is divisibleby 3 %} - {% if loop.index is divisibleby(3) %} - Control - Conditionals - {% if tasks\|length == 0 %} ¶ No tasks yet ¶ {% elif kenny.dead %} ¶ You killed kenny ¶ {% else %} ¶ print something ¶ {% endif %} - Loops - {{task}} - Accessing the parent Loop - The special loop variable always points to the innermost loop. If it’s desired to have access to an outer loop it’s possible to alias it: ¶ `<table>`{=html} ¶ {% for row in table %} ¶ `<tr>`{=html} ¶ {% set rowloop = loop %} {% for cell in row %} ¶ `<td id="cell-{{ rowloop.index }}-{{ loop.index }}">`{=html} ¶ {{ cell }} ¶ `</td>`{=html} ¶ {% endfor %} ¶ `</tr>`{=html} ¶ {% endfor %} ¶ `</table>`{=html} - Macros - Like functions - Expressions - Very similar to Python - string literals - numbers - calculations - Boolean - Similar to Python - Check length - {% if tasks\|length == 0 %} - Null-Master Fallback - Jinja2 supports dynamic inheritance and does not distinguish between parent and child template as long as no extends tag is visited. While this leads to the surprising behavior that everything before the first extends tag including whitespace is printed out instead of being ignored, it can be used for a neat trick. Usually child templates extend from one template that adds a basic HTML skeleton. However it’s possible to put the extends tag into an if tag to only extend from the layout template if the standalone variable evaluates to false which it does per default if it’s not defined. Additionally a very basic skeleton is added to the file so that if it’s indeed rendered with standalone set to True a very basic HTML skeleton is added: - {% if not standalone %}{% extends ‘master.html’ %}{% endif -%} ¶ `<title>`{=html} ¶ {% block title %}The Page Title{% endblock %} ¶ `</title>`{=html} ¶ `<link rel="stylesheet" href="style.css" type="text/css">`{=html} {% block body %} ¶ This is the page body. ¶ {% endblock %} - Alternating Rows - If you want to have different styles for each row of a table or list you can use the cyclemethod on the loop object: ¶ {{ row }} ¶ cycle can take an unlimited amount of strings. Each time this tag is encountered the next item from the list is rendered. - Highlighting Active Menu Items - Often you want to have a navigation bar with an active navigation item. This is really simple to achieve. Because assignments outside of blocks in child templates are global and executed before the layout template is evaluated it’s possible to define the active menu item in the child template: {% extends “layout.html” %} {% set active_page = “index” %} The layout template can then access active_page. Additionally it makes sense to define a default for that variable: {% set navigation_bar = \[ (’/’, ‘index’, ‘Index’), (’/downloads/’, ‘downloads’, ‘Downloads’), (’/about/’, ‘about’, ‘About’) \] -%} {% set active_page = active_page\|default(’index’) -%} … ¶ ¶ … - Using Jinja Templates in Code - Initialization - Setup, imports, environments, api - Default Folder for Templates: /templates - import os - import jinja2 - Initialize template engine in Python app - Hello World Code: - from flask import Flask import os import jinja2 template_dir = os.path.join(os.path.dirname(\_\_file\_\_), ‘templates’) jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir)) app = Flask(\_\_name\_\_) app.config\[’DEBUG’\] = True @app.route(”/”) def index(): template = jinja_env.get_template(’hello_form.html’) return template.render() - Specify where templates are stored - template_dir = os.path.join(os.path.dirname(\_\_file\_\_), ‘templates’) - Make new file system path by joining current path (of python file) with the specified path of the templates folder - an absolute path - Initiazlie the Jinja Templating Environment - jinja_env = jinja2.Environment(loader = jinja2.FileSysyemLoader(template_dir)) - Template loader is something that knows where the templates are stored and can find them when they need to be loaded - Or: - from jinja2 import Environment, PackageLoader, select_autoescape env = Environment( loader=PackageLoader(’yourapplication’, ‘templates’), autoescape=select_autoescape(\[’html’, ‘xml’\]) ) - This will create a template environment with the default settings and a loader that looks up the templates in the templates folder inside the yourapplication python package. Different loaders are available and you can also write your own if you want to load templates from a database or other resources. This also enables autoescaping for HTML and XML files. - Jinja2 uses a central object called the template Environment. Instances of this class are used to store the configuration and global objects, and are used to load templates from the file system or other locations. - Most applications will create one Environment object on application initialization and use that to load templates. In some cases however, it’s useful to have multiple environments side by side, if different configurations are in use. - named like regular .html files - template = jinja_env.get_template(’hello_form.html’) - template.render() - returns a rendered string from the template - with placeholder argument - template.render(name=first_name) - render_template Shortcut - part of Flask, not jinja, technically - Import render_template instead of jinja2 - can skip some steps like defining the template direcory and the jinja environment if your templates are located in the default /templates directory and you also want to auto escape and you don’t need to define a template variable before you want to return a template as in: template = jinja_env.get_template(’hello_greeting.html’) /newline return template.render(name=first_name) - from flask import Flask, request, redirect, render_template - render_template(’hello_greeting.html’, name=first_name) - Context - Jinja HTML Escaping - Autoescape - Add autoescape=True to jinja environment initialization - jinja_env = jinja2.Environment(loader = jinja2.FileSysyemLoader(template_dir), autoescape=True) - Safer but I think there might be performance considerations where you can use \| escape jinja functionality to easily escape a given string. - General Usage Ideas - Headers - Footers - Javascript - CSS - Sections