Skip to content
Home » Introduction to  Flask – Part 3 – Templates in Flask

Introduction to  Flask – Part 3 – Templates in Flask

Spread the love

In this part we’ll be talking about templates in Flask, about rendering HTML, the Jinja templating engine, redirecting, and so on.

You will find the code for this part on Github.

To start with, let’s clean our code a little bit. We don’t need all the routes we created in the previous part anymore. Let’s just leave the basic index route. Our app.py file should look like this:

As you can see, the index function returns a simple string. But what if we wanted it to return an HTML file?

Templates Folder and Template Files

 To keep the templates organized, let’s create a folder in the application root and name it templates:

templates folder

For the application to know where to look for the templates, we have to pass the template_folder argument in the constructor set to the name of that folder:

Now let’s create a basic index.html file inside the templates folder:

index template

Let’s add some basic structure to it. This is what you get using the Emmet extension in Visual Studio Code:

Let’s edit the title and add an h1 tag inside the body tag:

In order to render an HTML template, we need the render_template function from flask, so let’s import it:

Now, to return the template we just created, all we have to do is use this function with the name of the template as an argument:

If you now run the app, you’ll see the HTML file rendered:

render

Dynamic HTML Content

We can dynamically change the content of the HTML file. For example, we can define some variables in the index function and then use them in the HTML file. To do that, we can use the power of the Jinja templating engine.

The Jinja Templating Engine

Jinja is a rich templating language. It’s very popular in the Python ecosystem, not just in Flask. We’re not going to dive deep into the details of Jinja because this would definitely require a series of its own, but let’s at least have a look at some basics. So, back to our example, let’s define some variables in the index function and then use them in the HTML file:

Here we added two variables, a string and an integer. Let’s feed them into the HTML file and render them there dynamically. To do that, we just have to add the appropriate keyword arguments to the method:

Now we can access the variables in the HTML file using the Jinja templating engine. There are a couple delimiters available to separate Jinja code from HTML.

Jinja Delimiters

To use the variables we created, we use double curly braces:

The {{ }} delimiter is used for printing content to the output. If we now run the app, we’ll see the values there:

render

For statements that don’t produce any output we use the {% %} delimiter and for comments we use the {# #} delimiter.

Jinja Conditionals

To add conditional code to your templates, you just put it in the delimiters. Let’s add a list numbers to our index method in the app.py file:

Now, in the template, let’s display different content depending on the length of the list:

As you can see, we enclose the conditional code between the {% if %} and {% endif %} blocks. Besides, we use a length filter (after a pipe character, |) to read the length of the list. At this moment there are two elements in the list, so the {% elif %} block should take care of displaying the content:

render

Let’s remove the second element and leave just the number 3 in the list:

Now only the {% if %} block will be executed:

render

Finally, let’s add more elements to the list so that there are at least five:

Now only the {% else %} block will be executed:

render

Jinja Loops

In a similar way, we can loop through the list to display is elements in a list. We can use the {% for %} and {% endfor %} loops to do that.

Let’s implement it in the {% else %} block so that not only do we get the very vague information that there are lots of elements, but we also see them all listed:

This is how it’s rendered:

render

Template Inheritance

Templates can be inherited. We may want to repeat some of the stuff on each page in our application. We could achieve that by duplicating the code, but duplicating the code is not a good solution. A better way to approach this problem is to use the so-called base templates. These are templates other templates inherit from.

Let’s add a base.html file to the templates folder. In this file we can define the structure that we want to be shared by all the pages, let’s say something like this:

Here the title is dynamic. It’s set depending on the actual page that inherits from the base template. To use dynamic values, we specify blocks with names that we can then refer to. Here, the section for the title is named title. We also need an end block. Then, in a page that inherits from the base template, we will use this name to fill in the section accordingly. Between the start and end block we can put the default value for the title that will be displayed if the title is not set.

In a similar way, we created another block in the body and named it content. This is the part that will be different for each inheriting page.

We also added an h1 header. As it’s outside any block, it will be displayed on each page.

So, with our base template in place, we can inherit from it. In other words, we can extend it in other pages. Let’s do it in the index page.

First, we have to add the code to extend the base template at the top of the index.html file and remove everything that is not going to be part of the content, so the structure of the HTML file.

Next, we have to set the blocks that we defined in the base template to fill them in, so the title block and the content block. Let’s set the former to Home and the latter to the actual content of the index page. The index.html file should now look like this:

If we refresh the page in the browser, we’ll see the title (A), the header that will be displayed on each page because it’s part of the base template (B) and the actual content (C):

base template

Let’s create another page that extends the base template. In the template folder, add the contact.html file and fill it in like so:

Now, in the app.py file, we need to add a route for this page:

If we now navigate to /contact, we’ll see this:

render

As you can see, the header ‘Hey, welcome to our website.’ is still there, although it was not defined in the contact page. It’s inherited from the base template.

Filters

Another useful concept in the Jinja templating engine is filters. We already used a filter to determine the length of the list. But we can use filters to perform all kinds of operations.

To demonstrate how filters work, let’s create a new route and a new page that inherits from the base template. Here’s the route in the app.py file:

And now let’s add another page to the templates folder and name it fun_stuff.html. Here’s the code:

If you navigate to the fun_stuff page, you’ll see the following:

fun_stuff page

This isn’t much fun, so let’s play with the word a bit. In Jinja we cannot use regular Python functions like len to determine the length of a sequence or upper to convert the text to uppercase. Instead, we use filters, which are represented by the pipe character, which is the vertical line (|) that you can find on the keyboard above the Enter key, at least on my laptop.

So, let’s use the length filter that we used before, and also the upper filter to convert the text to uppercase. Well, if we really want to have fun, let’s add some more filters. Their names are usually self-explanatory and if you have any doubts about how they might work, you can look up the Jinja filters documentation. So, here’s the code:

Here’s what it looks like in the browser:

fun_stuff page

You can also define your own filters. Let’s define a filter that will return every other letter in the word. We can do it in the app.py file by defining a method with the @app.template_filter decorator:

Now, we’re ready to apply this filter:

Here’s what it looks like:

fun_stuff page

That’s basically all we need to know about filters. Let’s now move on to the next feature, which may be very useful, especially if your URL may change over time. The feature I’m talking about is dynamic URL.

Dynamic URLs

Let’s say we want to have a link from the index page to the fun_stuff page to easily get some fun every now and then. There is a route to that page in the app.py file:

Here the name of the endpoint is fixed, /fun_stuff. If this fixed endpoint name is fine, we can just add a regular link to it in the index page:

This will render like so:

render

If you click the link, you’ll navigate to the fun_stuff page.

But let’s create a dynamic link instead. This time we have to use the url_for function and pass to it the name of the function we want to be called when this link is clicked. At this point the name of the function is identical as the route itself (fun_stuff), but it doesn’t have to be the case. Anyway, here’s how we implement the dynamic URL in the link:

The link looks and works the same. It will even work if we change the route, for example like this:

Here the route is now /real_fun. Now the problem is that we can navigate directly to this page by typing in the new route in the browser. But what about the links from the index page? Let’s click them one by one. Let’s click on the link on the left first – it’s the one with the fixed URL:

links

This link doesn’t work anymore:

Not Found error

But the link on the right, so the one with the dynamic URL, still works:

Let’s change the route back to /fun_stuff so that both links work correctly.

Our last topic in this part of the series is redirecting.

Redirecting

Sometimes we don’t want to render any page in the browser, for example when a link is clicked. Instead, we may want to redirect the user to another specific page. To do that, we need to import the redirect function in the app.py file and use it in a route. We’ll create a new route to demonstrate it. So, here’s the imports section:

And here’s the new route:

This will redirect us to the index page. Let’s add the following link in the fun_stuff page:

You’ll see the link if you navigate to the fun_stuff page now:

render

And if you click it, you’ll be redirected to the index page again.

One thing to note… You can use dynamic URLs in the route as well. To do that, you have to import the url_for function:

and use it in the route:

It will still work the same.


Spread the love

Leave a Reply