Flask is a web framework for Python. It facilitates the creation of web apps (dynamic web pages).

Run Flask

Flask comes with its own server for debugging purposes, which can be started with:

flask run

Folder Structure

app.py               # main code
requirements.txt     # required libraries
static/              # files that never change
templates/           # dynamic files

“Hello, name” — Example App

templates/index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name = "viewport" content="initial-scale=1, width=device-width">
		<title>Hello</title>
	</head>
	<body>
		hello, {{ name_placeholder }} <!-- Jinja template -->
	</body>
</html>

app.py
http://website.domain/?name=Trude

from flask import Flask, render_template, request
app = Flask(__name__)
# When user visits / (the website root), load index.html.
# If the key name exists, store the value in a variable. If not, store world.
@app.route("/")
def index():
	name = request.args.get("name", "world")
	return render_template("index.html", name_placeholder=name)

HTML Form

Sample App

templates/index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name = "viewport" content="initial-scale=1, width=device-width">
		<title>Hello</title>
	</head>
	<body>
		<form>
			<input autocomplete="off" autofocus name="name" placeholder="Name" type="text">
			<button type="submit">Greet</button>
		</form>
	</body>
</html>

app.py
http://website.domain/?name=Trude

from flask import Flask, render_template, request
app = Flask(__name__)
# When user visits / (the website root), load index.html.
# If the key name exists, store the value in a variable. If not, store world.
@app.route("/")
def index():
	name = request.args.get("name", "world")
	return render_template("index.html", name_placeholder=name)

Custom Route

Both the form and /greet works.
templates/index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name = "viewport" content="initial-scale=1, width=device-width">
		<title>Hello</title>
	</head>
	<body>
		<form action="/greet" method="get">
			<input autocomplete="off" autofocus name="name" placeholder="Name" type="text">
			<button type="submit">Greet</button>
		</form>
	</body>
</html>

templates/greet.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name = "viewport" content="initial-scale=1, width=device-width">
		<title>Hello</title>
	</head>
	<body>
		hello,{{name}}
	</body>
</html>

app.py
http://website.domain/?name=Trude

from flask import Flask, render_template, request
app = Flask(__name__)
# When user visits / (the website root), load index.html.
# If the key name exists, store the value in a variable. If not, store world.
@app.route("/")
def index():
	name = request.args.get("name", "world")
	return render_template("index.html", name_placeholder=name)
@app.route("/greet")
def greet():
	return render_template("greet.html", name=request.args.get("name", "world"))

Avoid HTML Repetition

Use a layout instead of copying blocks.
templates/index.html

{% extends "layout.html" %}
{% block body %}
		<form action="/greet" method="get">
			<input autocomplete="off" autofocus name="name" placeholder="Name" type="text">
			<button type="submit">Greet</button>
		</form>
{% endblock %}

templates/greet.html

{% extends "layout.html" %}
{% block body %}
		hello, {{name}}
{% endblock %}

templates/layout.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name = "viewport" content="initial-scale=1, width=device-width">
		<title>Hello</title>
	</head>
	<body>
		{% block body %}{% endblock %}
	</body>
</html>

app.py
http://website.domain/?name=Trude

from flask import Flask, render_template, request
app = Flask(__name__)
# When user visits / (the website root), load index.html.
# If the key name exists, store the value in a variable. If not, store world.
@app.route("/")
def index():
	name = request.args.get("name", "world")
	return render_template("index.html", name_placeholder=name)
@app.route("/greet")
def greet():
	return render_template("greet.html", name=request.args.get("name", "world"))

Hide Sensitive Requests from the URL

Use post instead of get.
templates/index.html

{% extends "layout.html" %}
{% block body %}
		<form action="/greet" method="post">
			<input autocomplete="off" autofocus name="name" placeholder="Name" type="text">
			<button type="submit">Greet</button>
		</form>
{% endblock %}

templates/greet.html

{% extends "layout.html" %}
{% block body %}
		hello, {{name}}
{% endblock %}

templates/layout.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name = "viewport" content="initial-scale=1, width=device-width">
		<title>Hello</title>
	</head>
	<body>
		{% block body %}{% endblock %}
	</body>
</html>

app.py
http://website.domain/greet
The name doesn’t appear in the URL anymore.

from flask import Flask, render_template, request
app = Flask(__name__)
# When user visits / (the website root), load index.html.
# If the key name exists, store the value in a variable. If not, store world.
@app.route("/")
def index():
	name = request.args.get("name", "world")
	return render_template("index.html", name_placeholder=name)
@app.route("/greet", methods=["POST"])
def greet():
	return render_template("greet.html", name=request.form.get("name", "world"))

Combine Routes to save Resources

GET is always the default.
POST is used to send information to the server.
templates/index.html

{% extends "layout.html" %}
{% block body %}
		<form action="/" method="post">
			<input autocomplete="off" autofocus name="name" placeholder="Name" type="text">
			<button type="submit">Greet</button>
		</form>
{% endblock %}

templates/greet.html

{% extends "layout.html" %}
{% block body %}
		hello, {{name}}
{% endblock %}

templates/layout.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name = "viewport" content="initial-scale=1, width=device-width">
		<title>Hello</title>
	</head>
	<body>
		{% block body %}{% endblock %}
	</body>
</html>

app.py
http://website.domain/

from flask import Flask, render_template, request
app = Flask(__name__)
# When user visits / (the website root), load index.html.
# If the key name exists, store the value in a variable. If not, store world.
@app.route("/", methods=["GET, POST"])
def index():
	if request.method == "GET":
		return render_template("index.html")
	elif request.method == "POST":
		return render_template("greet.html", name=request.form.get("name", "world"))

Cookies - Session

Used to store data and to recognize the user.

  • Server → Client
    • Set-Cookie session=value
  • Client → Server
    • Cookie session
from flask import session
# Configure app
app = Flask(__name__)
# Configure session
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Redirect to login if no cookie exists
@app.route("/")
def index():
	if not session.get("name"):
		return redirect("/login")
	return render_template("index.html")
# EXAMPLES
# session is a dictionary
session["cart"] = []
books = db.execute("SELECT * FROM books WHERE id IN (?)", session["cart"])