Primer on Jinja Templating
Flask comes packaged with the powerful Jinja templating language.
For those who have not been exposed to a templating language before, such languages essentially contain variables as well as some programming logic, which when evaluated (or rendered into HTML) are replaced with actual values.
The variables and/or logic are placed between tags or delimiters. For example, Jinja templates use `
for expressions or logic (like for loops), while
` is used for outputting the results of an expression or a variable to the end user. The latter tag, when rendered, is replaced with a value or values, and is seen by the end user.
Note: Jinja Templates are just .html
files. By convention, they live in the /templates
directory in a Flask project. If you’re familiar with string formatting or interpolation, templating languages follow a similar type of logic—just on the scale of an entire HTML page.
Free Bonus: Click here to get access to a free Jinja Templating Resources Guide (PDF) that shows you tips and tricks as well as common pitfalls to avoid when working with the Jinja 2 templating language.
Quick Examples
Make sure you have Jinja installed before running these examples (pip install jinja2
):
Hello World!'
Notice how the actual output rendered to the user falls within the tags.
Flask Examples
The code can be found here.
Create the following project structure:
Activate a virtualenv, then install flask:
Add the following code to run.py:
Here, we are establishing the route /
, which renders the template template.html via the function render_template()
. This function must have a template name. Optionally, you can pass in keyword arguments to the template, like in the example with my_string
and my_list
.
Add the template:
Save this as template.html in the templates directory. Notice the template tags. Can you guess the output before you run the app?
Run the following:
You should see the following:
Note: It’s worth noting that Jinja only supports a few control structures: if
-statements and for
-loops are the two primary structures.
The syntax is similar to Python, differing in that no colon is required and that termination of the block is done using an endif
or endfor
instead of whitespace.
You can also complete the logic within your controller or views and then pass each value to the template using the template tags. However, it is much easier to perform such logic within the templates themselves.
Template Inheritance
Templates usually take advantage of inheritance, which includes a single base template that defines the basic structure of all subsequent child templates. You use the tags {% extends %}
and {% block %}
to implement inheritance.
The use case for this is simple: as your application grows, and you continue adding new templates, you will need to keep common code (like an HTML navigation bar, Javascript libraries, CSS stylesheets, and so forth) in sync, which can be a lot of work. Using inheritance, we can move those common pieces to a parent/base template so that we can create or edit such code once, and all child templates will inherent that code.
Note: You should always add as much recurring code as possible to your base template to save yourself time in the future, which will far outweigh the initial time investment.
Let’s add inheritance to our example.
Create the base (or parent) template:
Save this as layout.html.
Did you notice the {% block %}
tags? This defines a block (or area) that child templates can fill in. Further, this just informs the templating engine that a child template may override the block of the template.
Note: Think of these as placeholders to be filled in by code from the child template(s).
Let’s do that.
Update template.html:
So, the {% extends %}
informs the templating engine that this template “extends” another template, layout.html. This establishes the link between the templates.
Run it. You should see this:
One common use case is to add a navigation bar.
Add the following code to the base template, just after the opening <body>
tag:
Now, every single child template that extends from the base will have the same navigation bar. To steal a line from Java philosophy: “Write once, use anywhere.”
Super Blocks
If you need to render a block from the base template, use a super block:
Add a footer to the base template:
Here’s the updated code:
Run the app. You should see that the footer is just part of the base:
Now, add the super block to template.html:
Check it out in your browser:
The super block is used for common code that both the parent and child templates share, such as the <title>
, where both templates share part of the title. Then, you would just need to pass in the other part. It could also be used for a heading.
Here’s an example:
Parent
Let’s see that in action:
See what happens when you remove `
` from the child template.
Challenge: Try to update the <title>
using the same method with the super block. Check out my code if you need help.
Instead of hard coding the name of the template, let’s make it dynamic.
Update the two code snippets in template.html:
Now, we need to pass in a title
variable to our template from our controller, run.py:
Macros
In Jinja, we can use macros to abstract commonly used code snippets that are used over and over to not repeat ourselves. For example, it’s common to highlight the link of the current page on the navigation bar (active link). Otherwise, we’d have to use if
/elif
/else
statements to determine the active link. Using macros, we can abstract out such code into a separate file.
Add a macros.html file to the templates
directory:
Here, we’re using Flask’s request object, which is part of Jinja by default, to check the requested endpoint, and then assigning the active
class to that endpoint.
Update the unordered list with the nav navbar-nav
class in the base template:
Also, make sure to add the import at the top of the template: {% from "macros.html" import nav_link with context %}
.
Notice how we’re calling the nav-link
macro and passing it two arguments: the endpoint (which comes from our controller) and the text we want displayed.
Finally, let’s add three new endpoints to the controller:
Refresh the page. Test out the links at the top. Does the current page get highlighted? It should.
Custom Filters
Jinja uses filters to modify variables, mostly for formatting purposes.
Here’s an example:
This will round the num
variable. So, if we pass the argument num=46.99
into the template, then 47.0
will be outputted.
As you can tell, you specify the variable and then a pipe (|), followed by the filter. Check out this link for the list of filters already included within Jinja. In some cases, you can specify optional arguments in parentheses.
Here’s an example:
Now, besides the built-in filters, we can create our own.
Let’s add one of our own. One common example is a custom datetime filter.
Add the following code to our controller after we create the app, app = Flask(__name__)
:
Using the @app.template_filter()
decorator, we are registering the datetimefilter()
function as a filter.
Note: The default name for the filter is just the name of the function. However, you can customize it by passing in an argument to the function, such as @app.template_filter(formatdate)
.
Next, we are adding the filter to the Jinja environment, making it accessible. Now it’s ready for use.
Add the following code to our child template:
Finally, just pass in the datetime to our template:
current_time = datetime.datetime.now()
Test it.
Reference : https://realpython.com/primer-on-jinja-templating/
Last updated