Python and Flask

Python is high-level general purpose programming language. It's easy to learn and there are a lot of good resources available online. These notes do not aim to teach Python and only provide a brief overview of Flask.

Virtual environments

When doing a Python project, it's a good idea to contain it within a virtual environment. This allows you to install a library for one project without installing it everywhere. A good guide is https://python.land/virtual-environments/virtualenv. In Python 3.4 and above, you create the virtual environment by running python -m venv [directory]. Usually you want the virtual environment in your current directory, so run python -m venv venv. This will create a virtual environment in a directory called venv.
To activate the virtual environment, run venv.bat on Windows or
source venv/bin/activate on Linux or MacOS. You have to activate the virtual environment every time before you can use it. Once it's activated anything you install will only be installed inside it. You can then deactivate it by running deactivate.

Serialisation

Serialisation in Python is done using the pickle module.

>>> capitals = {'Greenland': 'Nuuk',
                'Luxembourg': 'Luxembourg',
                'Trinidad and Tobago': 'Port of Spain',
                'Romania': 'Bucharest'}
>>> serialised = pickle.dumps(capitals)
>>> print(serialised)
b'\x80\x04\x95c\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\tGreenland\x94\x8c\x04Nuuk\x94\x8c\nLuxembourg\x94h\x03\x8c\x13Trinidad and Tobago\x94\x8c\rPort of Spain\x94\x8c\x07Romania\x94\x8c\tBucharest\x94u.'
>>> loaded = pickle.loads(serialised)
>>> loaded == capitals
True

Data can be serialised to bytes (binary which anything can store) and then deserialised back into a Python object. This is useful for databases as they can't store Python objects but they can store binary.

A more widely used form of serialisation (not Python specific) is JSON (Javascript Object Notation). It is natively supported in Javascript and is often used for sending data between a client and server but is also widely supported by many programming languages and systems, making it an ideal language agnostic method of transferring data. In Python the json module provides loads and dumps methods for converting between JSON and Python dictionaries.

Flask

Flask is a web micro-framework written in Python. It is not installed by default so you need to install it with pip install flask. It provides a way to respond to requests using routes and send responses. It makes uses of Jinja for templates and has extensions for interfacing with databases, authentication and forms. A basic Flask app is shown below:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Website is working"

This app can be run with flask run from the command line.

The first line imports Flask and the second creates the Flask app. The __name__ helps Flask work out which folder it's in.

The @app.route is called a decorator and it says that the function defined below is how Flask should respond to a request for /, which is the root of your website. The function index is called whenever this request is made and the message it returns is sent as a response.

Basic forms

Suppose we have the form from the last section in a file called index.html in a directory called templates and the following Python file in the current directory:

from flask import Flask, request, render_template, redirect

app = Flask(__name__)

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

@app.route("/login", methods = ["POST"])
def login():
    print(request.form["username"] + "\n" + request.form["password"])
    return redirect("/")

Flask can get request parameters using the request object. You have to import this from flask. request.form allows you to access form parameters, request.method gives you the request method (usually GET or POST) and request.args.get(...) allows you to access the GET parameters. In the example above the username and password sent will be printed out. The "username" and "password" correspond to the name attributes of the inputs in the form.

Security

Passwords can be hashed using the Werkzeug security module. Generate a hash using
generate_password_hash(password) and check it using check_password_hash(hash, password).

Jinja

Flask templates use the Jinja template engine to produce HTML dynamically. Templates are stored in the templates directory. A Jinja template is just a normal HTML file but some parts are placeholders instead.
Example template:

<!DOCTYPE html>
<html>
    <head>
        <title>{{ title }}</title>
    </head>
    <body>
        {% if weekday %}
          <p>It's {{ dayOfWeek }}. You get 10% off!</p>
        {% else %}
          <p>Come back any time in the week to get 10% off.</p>
        {% endif %}
    </body>
</html>

The double braces are placeholders for expressions and the lines beginning with % are statements. For example, title will be replaced with the value of the variable title, which is passed to the template using render_template.
The if statement causes the template to render differently depending on whether it's a weekday or not. There are also % for % statements for iteration.

This template would be returned by a Flask route using

return render_template("index.html", title = "Special offer", weekday = True, dayOfWeek = "Wednesday")

It is also possible to include files in other templates using % include:

<main>
  ...
</main>
{% include "footer.html" %}
</body>