Build, Test, and Deploy a Flask Application: Part 1

Templates in Flask

Hoppa Digital
Better Programming
Published in
7 min readNov 17, 2019

--

Photo by freestocks.org on Unsplash

Meta Information About This Tutorial

Learning goals

  • Understand templates in Flask

Note: This tutorial is part of the series Learn Flask in a scientific way.

Source code

Planning and Design

Before we start building our application, we have to make a good plan. Our application at least needs seven pages to work:

  • Homepage: Present a list of mean reviews from different contributors.
  • About page: Introduce our service.
  • 404 page: When visitors request a page that doesn’t exist.
  • Register an account page: Allows people to register an account.
  • Login page: Allows users to log in.
  • Add a review page: Allows users to add a review (require login).
  • Update a review page: Allows users to update a review (require login).

Both “add a review page” and “update a review page” require user authentication first. To be succinct, we will leave these two pages out in our part 1 tutorial.

Project Setup

Here we will assume that you have installed Flask and venv, and understand their basic usage. If not, please read Build and Test a Mini Flask Application first.

  1. Create an empty repository named flask-app on GitHub and download it to the local environment (and navigate to the downloaded empty folder through the command line).
git clone https://github.com/your-username/mean-review-collector
cd mean-review-collector

2. Create a virtual environment in the downloaded, empty folder:

python3 -m venv env
source env/bin/activate

Getting Started

Based on what we learned from Build and Test a Mini Flask Application, we need at least two Python files for this application:

  • app.py: This is where the logic of our application lives; app handles all the routing and view functions.
from flask import Flask, make_responseapp = Flask(__name__)@app.route('/')
def home():
return 'home page'
@app.route('/about')
def about():
return 'about page'
@app.route('/register')
def register():
return 'register page'
@app.route('/login')
def login():
return 'login page'
@app.route('/<page_name>')
def other_page(page_name):
response = make_response('The page named %s does not exist.' \
% page_name, 404)
return response
if __name__ == '__main__':
app.run(debug=True)
  • app.test.py: This is where the testing of the above route and view functions happens.
import unittestfrom app import appclass BasicTestCase(unittest.TestCase):def test_home(self):
tester = app.test_client(self)
pages = ['/', 'about', 'register', 'login']
for page in pages:
response = tester.get(page, content_type='html/text')
self.assertEqual(response.status_code, 200)
def test_other(self):
tester = app.test_client(self)
response = tester.get('test', content_type='html/text')
self.assertEqual(response.status_code, 404)
if __name__ == '__main__':
unittest.main()

Even if all testing cases are passed, you will not have the intended effects rendered per page (when you check them through your browser), and you also lack a navigation bar.

To achieve such effects, you will need help from templates in Flask.

Templates

Templates in Flask are tools that manage presentation logic. Part of the content in each template is HTML code, while the other is logic (e.g., determine whether to show a page to unauthenticated users).

Flask uses Jinja 2 as the template engine to manage such logic. In its simplest form, a Jinja 2 template is just a file that contains static HTML code:

<h1>Hello world!</h1>

In a more complex form, a Jinja 2 template can just be a file that contains HTML code, variables, and logic to achieve various purposes.

For instance, the following code renders different text depending on if a visitor is authenticated:

{% if user %}  
<h1>Hello, {{ username }}! </h1>
{% else %}
<h1>Hello, Stranger! </h1>
{% endif %}

{{ … }} contains the variable name if you need to mix HTML with variables (in Python code).

{% … %} contains logic (such as conditional execution or loops). What goes inside it is basically Python code, as Jinja 2 is purely Python. The concept of opening and closing brackets applies here.

In other words, each opening {%…%} needs to be closed at the end with another {%…%}.

For a Flask application, all templates live under a folder named “templates” (for Flask to recognize them as templates). In other words, your Flask application will have the following structure when you extend it to include templates for each of the planned pages:

--- app.py
--- app.test.py
--- templates
--- home.html
--- about.html
--- register.html
--- login.html
--- 404.html

Beyond the syntax, it is important to understand the extendability of templates.

Web pages of the same application may share certain elements. For instance, we want our five pages to share exactly the same navigation bar.

In this case, we can carve out the common elements and put them in a different HTML file (base file), and let other HTML files extend the base file.

In our case, we call this base file base.html and place it under the templates folder. The structure of our application will be:

--- app.py
--- app.test.py
--- templates
--- home.html
--- about.html
--- register.html
--- login.html
--- 404.html
--- base.html

The base template contains:

<!doctype html>
<nav>
<h1>Mean Review Collector</h1>
<ul>
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('about') }}">About</a></li>
<li><a href="{{ url_for('register') }}">Register</a></li>
<li><a href="{{ url_for('login') }}">Login</a></li>
</ul>
</nav>
<section class="content">
<header>
{% block header %}{% endblock %}
</header>
{% block content %}{% endblock %}
</section>

url_for is a Flask method that generates a URL for the given endpoint.

For instance, url_for(‘home’) will return the URL for the home page. There are four links in our navigation bar (no bar so far), and that’s all this file contains. The section block is to define which structure other templates that extend base should follow — to have both a header and content blocks.

For instance, the template of our home page will extend base:

{% extends 'base.html' %}{% block header %}
<h1>{% block title %}Mean Reviews{% endblock %}</h1>
{% endblock %}
{% block content %}
<blockquote>
This paper is more appropriate for a speciality journal. Like,
one that specializes in terrible papers. - From @thirdreviewer
</blockquote>
<blockquote>
Before I can recommend acceptance, I request the following 272
changes to the manuscript. - From @thirdreviewer
</blockquote>
<blockquote>
Let me begin by apologizing for being so late with this review –
it took me much longer than expected to figure out how best to
insult all the authors. - From @thirdreviewer
</blockquote>
{% endblock %}

The first line {% extends ‘base.html’ %} indicates the extension.

The following sections follow the structure set by the base template and are filled up with three mean reviews. To render this template, we need to update our code in app.py:

from flask import Flask, render_template, make_responseapp = Flask(__name__)@app.route('/')
def home():
return render_template('home.html')
// more

We import the render_template method, so we can use it in our return statement to render the effects defined in our templates. When this method takes one parameter, the parameter has to be the template name.

Let’s launch the app:

python3 app.py

You will see:

The other templates extend the base template as well. To check what their code looks like, please refer to this page on GitHub. The app.py also needs to be updated:

from flask import Flask, render_template, make_responseapp = Flask(__name__)@app.route('/')
def home():
return render_template('home.html')
@app.route('/about')
def about():
return render_template('about.html')
@app.route('/register')
def register():
return render_template('register.html')
@app.route('/login')
def login():
return render_template('login.html')
@app.route('/<page_name>')
def other_page(page_name):
response = make_response(render_template('404.html'), 404)
return response
if __name__ == '__main__':
app.run(debug=True)

So far, we have implemented all the templates and a functioning navigation bar (not a bar yet). We still miss the style for this application.

Add Styles

To add styles to our application, we will use Bootstrap instead of writing our CSS file.

Bootstrap is an open-source framework from Twitter that helps you build webpages that are attractive and also compatible with all modern browsers. For more information about Bootstrap, see getbootstrap.com.

To add Bootstrap style to your base template, you simply need to add the following to the beginning of your base template (see the quick start instruction here):

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

After that, you need to make several changes to your template files. For instance, your HTML code for the first quote will change from:

<blockquote>
This paper is more appropriate ... in terrible papers. -From
@thirdreviewer
</blockquote>

To this:

<blockquote class="blockquote">
<p class="mb-0">This paper is more appropriate ... in terrible
papers.</p>
<footer class="blockquote-footer">From @thirdreviewer</footer>
</blockquote>

There is no point in memorizing anything here. All you need to do is to refer to the documentation of Bootstrap and search for what you need carefully.

In the above case, I searched for blockquotes. The code of all the updated templates can be found on GitHub. When you launch the application again, you will see:

Bootstrap makes our style adaptable to different sizes of screens. On mobile phones, tablets, or smaller screens, our application will look like:

Now you have successfully styled your Flask application. Don’t forget to push your code to GitHub.

This completes our second tutorial of Learn Flask in a scientific way.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Hoppa Digital
Hoppa Digital

Written by Hoppa Digital

Hoppa Digital (hoppadigital.com) is a digital agency that specializes in creating custom websites, mobile applications, and digital marketing strategies.

No responses yet

What are your thoughts?