Flask

In this reading, we will dig even deeper into Flask. We'll look at redirects and flashing, which are very cool. We'll look at the code for a small but complete Flask+PyMySQL web application. We'll also look at template inheritance in Jinja2.

GET vs POST

The first part of the reading discusses the flask request object, which holds information that comes from the browser. As we learned in the last reading (HTTP methods), there are several kinds of requests in the HTTP protocol, but the two most important are GET and POST.

The W3Schools has a good and concise summary of GET versus POST. That's a fairly short page; please read all of it.

Flask Tutorials

Please read the following:

People App Example

Please review this code for the people_app example.

Flask and PyMySQL

We can combine Flask and PyMySQL in a fairly obvious way. In fact, if we import the same people.py script (module) that we did recently, the code becomes pretty easy.

This code is in the people_app folder in the cs304 course account. In class, we'll construct it together, where I'll use the cs304guest account.

Here's the code for people_app/app.py:

'''Flask/PyMySQL app to list the people in the WMDB. 

Scott D. Anderson
revised Fall 2019 for Python3
revised Spring 2020 for new dbi module
'''

from flask import (Flask, url_for, render_template)
import cs304dbi as dbi
import servertime
import people

app = Flask(__name__)

@app.route('/')
def hello_world():
    tmpl = '''<h1>Hello Everyone!</h1>
             <p>Click here for <a href="{url1}">people list</a></p>
             <p>Click here for <a href="{url2}">list of people born in June</a></p>
           '''
    page = tmpl.format(url1=url_for('people_list'),
                       url2=url_for('people_born_in_month',month=6))
    return page

@app.route('/people/')
def people_list():
    conn = dbi.connect()
    folk = people.get_people(conn)
    now = servertime.now()
    return render_template('people-list.html', 
                          desc='WMDB People as of {}'.format(now), 
                          people=folk)

month_names = ['skip', 'January', 'February', 'March',
               'April', 'May', 'June',
               'July', 'August', 'September',
               'October', 'November', 'December' ]

@app.route('/people-born-in/<int:month>')
def people_born_in_month(month):
    conn = dbi.connect()
    folk = people.people_born_in_month(conn,month)
    head = 'WMDB People born in {}'.format(month_names[month])
    return render_template('people-list.html', 
                          desc=head,
                          people=folk)

@app.before_first_request
def startup():
    dbi.cache_cnf()
    dbi.use('wmdb')

if __name__ == '__main__':
    import os
    uid = os.getuid()
    app.debug = True
    app.run('0.0.0.0',uid)

Notice that we now have to import render_template from flask. We also import url_for.

Observations

  • The app is wonderfully compact and modular!
  • The verbose HTML and CSS is relegated to a template file that we only have to look at when we want to
  • The database interaction is in a separate module, allowing us to test it before we even start working on our app, or letting someone else from the team handle it.

Also:

  • The database connection is created with every single request.
  • It might seem smart to just create one connection that can be shared over many requests. That could be a significant increase in efficiency; however ...
  • There may be trouble when we get to deployed apps, which are multi-threaded. We'll talk about concurrency and multi-threading later in the course.

Startup Code

An app sometimes has to do some stuff when it starts up. We could put that below the magic line separating the module from the script, but that doesn't work as well when the app is deployed. However, Flask solves that by having a different decorator to declare a function that should be executed before the first request:

@app.before_first_request
def startup():
    dbi.cache_cnf()
    dbi.use('wmdb')

Once that runs, each request just has to do dbi.connect().

Templates

All the templates for a flask app are kept in a templates folder, next to our app.py (or whatever we call it).

Here's the code for the people_app/templates/people-list.html file:

<!DOCTYPE html>
<html>
    <head>
        <title>Database People</title>
    </head>
    <body>

    <h1>List of {{ desc }}</h1>

    <article>
        <ol>
            {% for person in people %}
            <li>{{ person.name }} born on
                {{ person.birthdate }}</li>
            {% endfor %}
        </ol>
    </article>
    </body>
</html>

That's a complete, working Flask+PyMySQL web application. We'll play with it a bit in class.

Jinja2

Why use templating at all? Most websites have many pages, but with a common look and infrastructure (CSS files, JS files, etc). There's actually quite a lot of that boilerplate in this reading file (do a "view source" to see). I finally adopted a templating scheme for the CS 304 website, so if I decide to add or remove an infrastructure file, or to change some of the common markup, I don't have to update all umpteen pages of this site. It used to be a nightmare.

So, don't make my past mistake. If the common boilerplate is saved in a file, called a template, our web application (our Python code) can dynamically fill in the variable stuff (such as information pulled from the database). If we need to change the common stuff, it can easily be done by editing just one file.

Jinja2 Inheritance

Very often, the pages of a website have an overall theme, but with variations:

  • All of the pages will have some standard infrastructure (CSS files, JavaScript files, links to external resources like Bootstrap or JQuery ...).
  • All of the "top-level" pages will have the same nav bar, logo, and other kinds of content.
  • Lower level pages will have variant nav bars, maybe smaller logos, links to top-level pages, etc.
  • Every page will have its own title, header, etc.

How to balance all this? If we make a very fundamental change (maybe change our logo?) we might have to change all our templates. This is way better than having to update every page, but it still allows errors to creep in (you update some but not all of the templates).

A better, more sophisticated, approach is to use inheritance, where a base template is very abstract, with chunks (blocks) that are filled in by the child templates. For example, the CS 304 site could have a base template that supplies the overall structure, CSS, jQuery and JavaScript files. Then child templates could be used for readings (like this file), lecture activities, assignments, and other kinds of pages.

Jinja2 allows inheritance like this.

Primer on Jinja Templating. This does a nice job of describing inheritance

Inheritance

Suppose we have the following three templates:

The first is a general template for the whole site. Here's what it looks like:

<!doctype html>
<html lang='en'>
<head>
    <meta charset='utf-8'>
    <meta name=author content="Scott D. Anderson">
    <title>{{title}}</title>
    {% block headstuff %}{% endblock %}
</head>
<body>

{% block content %}

<h1>{{title}}</h1>

<article>Lorem ipsum ...</article>

{% endblock %}

<footer>
    {% block footer %}
    Default Copyright notices and stuff
    {% endblock %}
</footer>

</body>
</html>

It can be rendered directly, but more importantly, the three named blocks can be overridden in the two child templates. The named blocks are

  • headstuff, which is empty
  • content, which is a generic page with just one placeholder: title
  • footer, which has the copyright notice and such.

Here's the first child template, called reading.html

  • It replaces all three named blocks.
  • It replaces the headstuff block with something non-empty, thereby adding some CSS to the page
  • It replaces the content with code that has three placeholders: title, classdate and article
  • It replaces the footer with a specific copyright notice.
{% extends "base.html" %}

{# additional stuff for the head #}
{% block headstuff %}
<style> .optional { color: gray; }</style>
{% endblock %}

{# replaces default content block #}
{% block content %}
<h1>Reading on {{title}}</h1>

<p>Please read the following before class on {{ classdate }}

<article>{{ article }}</article>
{% endblock %}

{# replaces default footer #}
{% block footer %}
&copy; 2019 Scott D. Anderson and the CS 304 staff
{% endblock %}

Now there are an additional tags (holes to fill), namely classdate and article

Schematic

Here's an idea of the overall structure:

A base template and two templates that inherit it
A base template and two templates that inherit it

Note that everything in the child must be in a block. Anything else is ignored. The purpose of a child is to re-write one or more blocks. If you have no re-writes, the child is unnecessary.

Thus, children are very different from parents. I often see mistakes in student code where they copy/modify the base to be the child, but that's not right.

The parent has HTML with named blocks.

The children only has a specification of the parent, and replacements for the named blocks. The child doesn't have to replace all of the named blocks.