Flask 4 - Jinja & Templates
Jinja, templates, rendering a template, passing dynamic data through our template
Let’s get into it
1 - Jinja
Jinja is a tool that lets you use Python to dynamically fill in HTML templates. This is handy when you've got elements like headers and footers that repeat across many pages of a website. Instead of updating every single page when you make a change to these common elements, you can just update your template in one place.
Although you can use Jinja without Flask, they are often used together because Flask was actually built to integrate seamlessly with Jinja. Flask comes with Jinja included and generally expects you to keep all your Jinja templates in a folder called templates within your project.
When you're ready to show a page, Flask takes over to "render" these templates. This means it reads your Jinja template, swaps in any data that needs to be dynamic (like user names or dates), and converts it all into regular HTML that the user's browser can display. This all happens behind the scenes, which can seem a bit confusing at first, but we'll go through it step by step to clear things up.
2 - Templates
To start using Jinja templates in your app, the first thing you need to do is create a special folder for them. So, head over to your project directory, and make a new folder named templates. Make sure to spell it exactly like that, as Flask is particular about the name and it’s case sensitive (don’t forget the s).
At its simplest, a Jinja template is just an HTML file. We're going to stick with using the .html file extension for all our Jinja templates. Inside your new templates folder, create a file called home.html. This file will be the main page that users see when they visit your app, and it will hold all the HTML content that we used to keep directly in our Python code.
For now, just pop some basic HTML into this file. We'll dive into how to add dynamic, changing data from Python to our templates in the next step:
<html>
<head>
<title>Headlines</title>
</head>
<body>
<h1>Headlines</h1>
<b>title</b><br />
<i>published</i><br />
<p>summary</p>
</body>
</html>
Now, instead of cobbling together a string of HTML in our Python code, we'll just use our new template and send that back instead. In your main.py file, start by adding this import line at the top:
from flask import render_template
The render_template function transforms a Jinja template into pure HTML that any web browser can understand. For now, though, we're just using it with plain HTML, so what goes in is pretty much what comes out, and you'll see exactly that in your browser.
3 - Rendering a basic template
In your get_news() function, go ahead and remove the old return statement that sends back the big block of HTML. Keep the earlier lines that pull data using feedparser—we'll need that shortly. Next, we'll update the return statement to make the get_news() function look like this:
@app.route("/")
@app.route("/<publication>"
def get_news(publication="bbc"):
feed = feedparser.parse(RSS_FEEDS[publication])
first_article = feed['entries'][0]
return render_template("home.html")
Even though our HTML file is just plain HTML for now and doesn’t use any Jinja specific code yet, there’s still some neat stuff happening. When you call the function, it looks for the home.html file in our templates folder, reads it, checks for any Jinja bits (though there aren’t any right now), and turns it into an HTML string that it sends back to the user. Once you've updated everything, go ahead and restart your app, then hop into your web browser to check it out.
It might seem like we’ve taken a step back, because if you look at your page now, instead of seeing actual news, you’ll just see placeholder words like title, published, and summary. But this setup is getting us ready to do some more advanced stuff soon.
4 - Passing dynamic data through our template
Next, we'll tweak our Python file a bit to send the data we want to show on the web page. Just update your get_news() function again. This time, you'll pass all the necessary data to the render_template() function as named arguments, like this:
@app.route("/")
@app.route("/<publication>")
def get_news(publication="bbc"):
feed = feedparser.parse(RSS_FEEDS[publication])
first_article = feed['entries'][0]
print(first_article)
return render_template("home.html",title=first_article.get("title"),published=first_article.get("published"),summary=first_article.get("summary"))
The render_template function uses the name of your template file as its first argument. After that, you can pass it as many named variables as you want. These variables are then available in your template, and you can use them by their names to display their data on the web page.
In your home.html file, to use the data you're passing in, just wrap your placeholders with double curly braces. So, you'll change it to look something like this:
<html>
<head>
<title>Headlines</title>
</head>
<body>
<h1>Headlines</h1>
<b>{{title}}</b><br />
<i>{{published}}</i><br />
<p>{{summary}}</p>
</body>
</html>
In your home.html file, when you use double curly braces like {{ }}, you're telling Jinja that whatever's inside isn't just regular HTML text—it's a placeholder for data. Since the placeholders, like `title`, `published`, and `summary`, match the names of the variables you're passing to render_template, Jinja knows to swap those placeholders with actual data from your variables. This way, when the page is rendered, it's filled with real data instead of just placeholder text.
Go ahead and test it to see the real news data on your page again.