Web: Flask and Jinja2

Flask

Flask a microframework written in Python that makes it easy to get a simple web application up and running with some features that can be useful in the development process.

Install package Flask, create new application.py file with the code and set FLASK_APP=application.py

To start server: flask run

# Import the class `Flask` from the `flask` module
from flask import Flask

# Instantiate a new web application called `app`, with `__name__` representing the current file
app = Flask(__name__)

# A decorator; when the user goes to the route `/`, execute the function
@app.route("/") 
def index():
    return "Hello, world!"

A route is the part of the URL that determines which page is being requested. The route for the default page is simply “/”.

#when the user goes to the route `/Dmitry'
@app.route("/Dmitry") 
def name():
    return "Hello, Dmitry!"
#when the user goes to the route `/<any>`
@app.route("/<string:user_name>")
def name_variable(user_name):
    user_name1 = 'Mr ' + user_name.capitalize()
    return f"Hi, {user_name1}!"

HTML files

Separate HTML files can be rendered (render_template function from Flask module) with variables:

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/<string:name>")
def index(name):
    return render_template("index.html", var_name=name)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body {
            text-align: center
        }
    </style>
</head>
<body>
<h1>Hello, {{ var_name }} </h1>
</body>
</html>

These templates are rendered using a separate templating language called Jinja2.


Jinja2

Jinja is a modern and designer-friendly templating language for Python.

  • In .py: return render_template(“index.html”, var_name=name)
  • In html: <h1>Hello, {{ var_name }} </h1>

Jinja2 allows conditional statements:

{% if var_name %}
    <h2>Yes!</h2>
    <h3>Hello, {{ var_name }}</h3>
    <p></p>
    <a href="{{ url_for('loop') }}">See more...</a>
{% else %}
    <a href="{{ url_for('index') }}">Go back</a>
{% endif %}
  • Loops:
<ul>
    {% for each in list %}
        <li>{{ each }}</li>
    {% endfor %}
</ul>

If there are multiple routes on the Flask server, then one route can link to another as so:

<a href="{{ url_for('func_name') }}">See more...</a>

func_name is the name of a function associated with a route.

@app.route("/")
def index():
    name = True
    return render_template("index.html", var_name=name)

@app.route("/looplist")
def loop():
    name = False
    my_list = ['AA', 'BB', 'CC']
    return render_template("index.html", var_name=name, list=my_list)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body {
            text-align: center
        }
    </style>
</head>
<body>
<h1>This is constant!</h1>
<p></p>
<p></p>
    {% if var_name %}
        <h2>Yes!</h2>
        <h3>Hello, {{ var_name }}</h3>
        <p></p>
        <a href="{{ url_for('loop') }}">See more...</a>
    {% else %}
        <ul>
            {% for each in list %}
                <li>{{ each }}</li>
            {% endfor %}
        </ul>
        <a href="{{ url_for('index') }}">Go back</a>
    {% endif %}

</body>
</html>

Jinja2 ‘template inheritance’

Create some kind of layout with variables in blocks:

<!DOCTYPE html>
<html>
    <head>
        <title>My Website!</title>
        <style>
            body { text-align: center}
        </style>
    </head>
    <body>
        <h1>{% block heading %}{% endblock %}</h1>

        {% block body %}
        {% endblock %}
    </body>
</html>

In the different HTML files, just extend with the layout and fill blocks.

index.html:

{% extends "layout.html" %}

{% block heading %}
    Index Page
{% endblock %}

{% block body %}
        <h2>Hello, {{ var_name }}</h2>
        <a href="{{ url_for('loop') }}">See more...</a>
{% endblock %}

loop.html:

{% extends "layout.html" %}

{% block heading %}
    Loop page
{% endblock %}

{% block body %}
        <ul>
            {% for each in list %}
                <li>{{ each }}</li>
            {% endfor %}
        </ul>
        <a href="{{ url_for('index') }}">Go back</a>
{% endblock %}

application.py

@app.route("/")
def index():
    name ='User'
    return render_template("index.html", var_name=name)

@app.route("/loop")
def loop():
    my_list = ['AA', 'BB', 'CC']
    return render_template("loop.html", list=my_list)

Forms

the results from HTML forms can now be actually stored and used.

<form action="get-ip-address" method="post">
<input type="text" name="ip_address" placeholder="Enter IP Address">
<button>Add</button>
<form>
  • action attribute lists the route that should be ‘notified’ when the form is submitted
  • method attribute is how the HTTP request to submit the form should be made
  • name attribute of the input

The Python code to process this form: import request

from flask import Flask, render_template, request
app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/get-ip-address", methods=["POST"])
def print_ip_address():
    # take user request, access form, get var nam and store in ip_address
    ip_address = request.form.get("ip_address")
    return render_template("ip_address.html", ip_address=ip_address)

If there are multiple request methods: list of methods and ifelse

@app.route("/get-ip-address", methods=["POST", "GET"])
def print_ip_address():
    if request.method == "GET":
        return "Please submit the form"
    else:
        ip_address = request.form.get("ip_address")
        return render_template("ip_address.html", ip_address=ip_address)

Sessions

Sessions are how Flask can keep track of data that pertains to a particular user: could be a global variable (access to all users) or per user(cookies). Install Flask-Session

from flask import Flask, render_template, request, session
from flask_session import Session

app = Flask(__name__)

app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"

Session(app)

@app.route("/", methods=["GET", "POST"])
def index():
    if session.get("ip_address") is None:
        session["ip_address"] = []
    if request.method == "POST":
        ip_address = request.form.get("ip_address")
        session["ip_address"].append(ip_address)
    return render_template("index.html", ip_addresses=session["ip_address"])
{% extends "layout.html" %}

{% block heading %}
    Index Page
{% endblock %}

{% block body %}
    <ul>
        {% for each in ip_addresses %}
            <li>{{ each }}</li>
        {% endfor %}
    </ul>
    <form action="/" method="post">
    <input type="text" name="ip_address" placeholder="Enter IP Address">
    <button>Add</button>
    <form>
{% endblock %}

Run app from the script

from flask import Flask, render_template, request, session
from flask_session import Session

app = Flask(__name__)

if __name__ == '__main__':
    app.debug = True
    app.run()

Debug mode

For every change in the files, the flask server must be restarted to apply those changes. With debug mode enabled – all changes are applied on the fly and no need to re-run flask

set FLASK_ENV=development

For more: Flask Documentation

Share

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *