Tehnologii Web/2022-2023/Laborator 8
Templates in Flask
editWe need to make sure that the environment and Flask are installed, then we can start building the application. Flask's render_template() helper function will be used to connect the Python side with the HTML template side. It will be observed how to pass the variable from the application side to the templates.
Rendering a template and variables usage
editThe following code sequence is entered in the app.py file:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello():
return render_template('index.html')
In the above code, the Flask class and the render_template() function from the flask package have been imported. We use the Flask class to create the Flask application instance named app. Next, we defined a view function (which is a Python function that returns an HTTP response) called hello() using the @app.route() decorator, which converts a regular function to a view function. This view function uses the render_template() function to render a template file named index.html.
Next, we need to create the template file named index.html, in a directory named templates, in the flask_app directory. It is important for the directory to be named templates.
In the file index.html next code will be inserted:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Flask</title>
</head>
<body>
<h1>Hello, World!</h1>
<h2>Welcome to a simple Flask application!</h2>
</body>
</html>
După introducerea codului în index.html, se rulează aplicația cu flask run. In web applications, we often need to transfer data from the application's Python files to HTML templates. To demonstrate how to do this in this application, we will introduce a variable containing the current UTC date and time to the index template and display the value of the variable in the template, that is, on the HTML page.
import datetime
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello():
return render_template('index.html', utc=datetime.datetime.utcnow())
Here we imported the datetime module and transfer a variable called utc to the index.html template with the value datetime.datetime.utcnow() which is the current UTC date and time. Next, go to the index.html file and add the variable to the template file using Jinja2 technology.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Flask</title>
</head>
<body>
<h1>Hello, World!</h1>
<h2>Welcome to a simple Flask application!</h2>
<h3>{{ utc }}</h3>
</body>
</html>
The display will be the same as in the previous section, only the part with the current date and time using the UTC zone will be added.
We've created an index page with an HTML template in our Flask application, we rendered a template, and transferred and displayed a variable value from Python Flask to HTML. Next, we will discuss avoiding code repetition using template inheritance.
Using template inheritance
editIn this subchapter, we will create a basic template with content that can be shared with the other templates. We will edit the index template to inherit from the base template. Next, we'll create a new page that will serve as the About application page, where users of the application can find additional information about it. A base template contains HTML components that are typically shared between all other templates, such as the application title, navigation bar, and footers.
A file called base.html will be created in the templates directory, and the following code lines will be introduced in the file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock %}: FlaskApp</title>
<style>
nav a {
color: #d64161;
font-size: 3em;
margin-left: 50px;
text-decoration: none;
}
</style>
</head>
<body>
<nav>
<a href="#">FlaskApp</a>
<a href="#">About</a>
</nav>
<hr>
<div class="content">
{% block content %} {% endblock %}
</div>
</body>
</html>
Most of the code from this file is standard HTML, a title, a style for the navigation links, a navigation bar with two links, one for the index page and one for the not-yet-created About page, and a <div> for the content page. The following text will clarify the meaning of the Jinja code lines.
- {% block title %} {% endblock %}: A block that serves as a placeholder for a title. Later, we'll use it in other templates to provide a custom title for each page in our application without rewriting the entire <head> section each time.
{% block content %} {% endblock %}: Another block that will be replaced with some content, depending on the child template, a template that inherits from base.html, that will replace it.
To take advantage of the inheritance process, the following code will be inserted into the index.html file.
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Index {% endblock %}</h1>
<h1>Hello, World!</h1>
<h2>Welcome to a simple Flask application!</h2>
{% endblock %}
The {% extends %} tag is used to inherit from the base.html template. It then extends by replacing the content block in the base template with what is inside the content block in the index.html file.
This content block contains an <h1> tag with the text Index inside a title block, which in turn replaces the original title block from the base.html template with the text Index, so the full title becomes Index: Simple Flask. This way, the repetition of the same text will be avoided as it works both as a title for the page and as a title that appears below the navbar inherited from the base template.
The same procedure is done with the About page.
Creating the links
editFor this, the previous code could be taken into account, however, the base.html template must be modified.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock %}: Simple Flask</title>
<style>
nav a {
color: #d64161;
font-size: 3em;
margin-left: 50px;
text-decoration: none;
}
</style>
</head>
<body>
<nav>
<a href="{{ url_for('hello') }}">Simple Flask</a>
<a href="{{ url_for('about') }}">About</a>
</nav>
<hr>
<div class="content">
{% block content %} {% endblock %}
</div>
</body>
</html>
We will use the special function url_for() which will return the URL for the view function you give it. The first link connects to the route of the hello() view function, which is the index page. The second link connects to the about() view function route. Note that we are transferring the name of the view function, not the path.
Using the url_for() function to create URLs help us manage URLs well. If URLs are encoded, links will break if routes are edited. With url_for() one can edit routes and guarantee that links will still work as expected.
Using Conditions and Loops
editThe if statement will be used to control what to display based on certain conditions. We will also use for loops to iterate through lists created in Python and display each element from the list.
Example. In the app.py file:
@app.route('/mesaje/')
def mesaje():
mesaje = ['Primul mesaj.',
'Al doilea mesaj.',
'Al treilea mesaj.',
'Al patrulea mesaj.'
]
return render_template('mesaje.html', mesaje=mesaje)
It will return a template file called mesaje.html on the last line, passing a variable called mesaje that contains the list of the template file. Go to the mesaje.html file and enter the code:
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Mesaje {% endblock %}</h1>
<div style="width: 50%; margin: auto">
{% for i in mesaje %}
<div style="padding: 10px; background-color: #EEE; margin: 20px">
<p style="font-size: 24px">{{ i }}</p>
</div>
{% endfor %}
</div>
{% endblock %}
It will display, in four identical rectangles, styled as it was specified in the code, the four messages.
Example. This is how to display the odd rectangles with a different color than the even ones.
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Discurs {% endblock %}</h1>
<div style="width: 50%; margin: auto">
{% for i in mesaje %}
{% if loop.index % 2 == 0 %}
{% set bg_color = '#e6f9ff' %}
{% else %}
{% set bg_color = '#eee' %}
{% endif %}
<div style="padding: 10px; background-color: {{ bg_color }}; margin: 20px">
<p>#{{ loop.index }}</p>
<p style="font-size: 24px">{{ i }}</p>
</div>
{% endfor %}
</div>
{% endblock %}
Note the if statement.
Exercise
editCreate a new program, on a topic of your choice, that has the elements from this lab:
- rendering a template that inherits from a base template,
- for loops and if conditions using Jinja
These should be applied to two different pages for different functionalities.