Flask

Download Demo

To download the demo code for this lecture, run the following:

$ hbget flask --demo

Intro

Objectives

  • What is a Framework?

  • A basic Flask app

  • Form handling

Web Frameworks

A Quick Demo

(env) $ python3 server.py
* Running on http://localhost:5000/ (Press CTRL+C to quit)
* Restarting with stat

What is a Web Server?

A program that’s running on a machine and waiting for a web request.

The word “web server” has many different connotations

“Web server” is a generic word that’s used to describe a technology that can communicate over HTTP, the communications protocol used on the internet. The term can be used to describe software and hardware.

Here, the word “web server” refers to software — we are using it to refer to our Python Flask application.

digraph browserserver { rankdir=LR; subgraph cluster0 { margin=8; pencolor="firebrick3"; label="Request"; fontcolor="firebrick3"; browser [label="Web Browser" shape="box"]; server [label=<Web Server<BR/><I>server.py</I>> shape="doubleoctagon" style="filled" fillcolor="chartreuse1"]; browser -> server [label=<Can I have my profile, please?>]; } }

The server then responds with HTML text for that page:

digraph browserserver { rankdir=LR; subgraph cluster1 { margin=8; pencolor="firebrick3"; label="Response"; fontcolor="firebrick3"; browser1 [label="Web Browser" shape="box"]; server1 [label=<Web Server<BR/><I>server.py</I>> shape="doubleoctagon" style="filled" fillcolor="chartreuse1"]; browser1 -> server1 [dir="back" label=<<I>A Web Page!</I><BR/>&lt;html&gt;...&lt;/html&gt;>]; } }

Web Application

A web application is a program that can “listen” for web requests and respond to them

GET /hello     (http://server/hello)

<html>
  <body>
    <h1>Hello</h1>
  </body>
</html>

The HTML example above is actually incomplete

To keep code samples short in the presentation, we’re eliding some less-important HTML markup. The shortest valid HTML skeleton in modern HTML would actually be:

<!doctype html>
<html>
  <head>
    <title>Hello</title>
  </head>
  <body>
    <h1>Hello</h1>
  <body>
</html>

What Do Web Applications Need To Do?

  • handle web requests

  • produce dynamic HTML

  • handle forms

  • handle cookies

  • connect to databases

  • provide user log-in/log-out

  • cache pages for performance

  • & more!

Flask is a Web Framework

  • Set of functions, classes, etc. that help you define

    • Which requests to respond to

      • http://server/hello

      • http://server/profile

    • How to respond to requests

      • Show the message “Hello”

      • Show the user’s name and profile.

  • Someone else wrote these functions, classes, etc.

    • You’ll use them.

  • Like a library, but bigger and more opinionated

  • Usage is similar to the Python Standard Library.

Importing functions from the standard library
from random import choice, randint
Importing functions from Flask
from flask import request, render_template

Flask Apps

Installing Flask

$ virtualenv env
New python executable in env/bin/python
Installing setuptools, pip...done.

$ source env/bin/activate

(env) $ pip3 install flask
... lots of stuff ...
Successfully installed flask Werkzeug Jinja2 itsdangerous markupsafe
Cleaning up...

A Minimal Flask App

from flask import Flask


app = Flask(__name__)


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

What is __name__?

When we create a Flask application, it needs to know what module to scan for things like routes (covered later) — so the __name__ is required and should always be written like that.

if __name__ == '__main__' tells Python to execute code if you’re running a script directly.

Making Responses

Flask responds to web requests by calling functions

  • A function that returns web response is called a view function

    • Response is a string

    • Usually, a string of HTML

  • So, our function returns an HTML string:

    def say_hello():
        """Return simple 'Hello' Greeting."""
    
        return '<html><body><h1>Hello</h1></body></html>'
    

Routing Requests

Routes tell Flask which URL should correspond with which function

@app.route('/hello')
def say_hello():
    """Return simple 'Hello' Greeting."""

    return '<html><body><h1>Hello</h1></body></html>'
  • Flask lets you “route” a URL to a function

  • @app.route('/hello') is a Python “decorator”

    • a decorator adds additional functionality (in this case from Flask) to your function

    • /hello is the URL we requested

Serving at the Root

The root URL is used to show a web site’s homepage

@app.route('/')
def index():
    """Show homepage"""

    return """
    <html>
    <body>
      <h1>I am the landing page</h1>
    </body>
    </html>
    """

This function will get called if we go to http://localhost:5000/

Forms

Connecting Forms with Routes

A form element will submit data to the URL in its action attribute:

<form action="/greet">
  What's your name?
  <input type="text" name="person">
  <input type="submit">
</form>

Accessible HTML forms

For the sake of brevity, this code doesn’t include good practices for accessibility in web design. A much better form would be:

<form action="/greet">

  <label for="name-input">Name:</label>
  <input type="text" name="name" id="name-input" />

  <label for="compliments-checkbox">Want compliments?</label>
  <input type="checkbox" name="wants_compliments" id="compliments-checkbox" />

  <input type="submit" />

</form>

or

<form action="/greet">
  <label>What's your name? <input type="text" name="person"></label>
  <input type="submit">
</form>

Now screenreaders for blind users of our site would know which label is the the descriptive label for each form element. This kind of stuff is really important for building a website that is usable for people with visual impairment disabilities.

Sending a Form to the Browser

_images/form.png
@app.route('/form')
def show_form():
    """Greet user and ask for name."""

    return """
    <!doctype html>
    <html>
    <head>
      <title>Hi There!</title>
    </head>
    <body>
      <h1>Hi There!</h1>
      <form action="/greet">
        What's your name?
        <input type="text" name="person">
        <input type="submit">
      </form>
    </body>
    </html>
    """
  • Now, when the user visits http://server/form, there’s a form there.

  • The user can interact with the form, and press submit.

  • The form submits its values to route specified in the form’s action attribute.

<form action="/greet">
  What's your name?
  <input type="text" name="person">
  <input type="submit">
</form>

This form is going to submit its values to the route with @app.route('/greet') on top of it.

Handling Forms

Here is where our form goes when the user submits.

@app.route('/greet')
def offer_greeting():
    """Greet user with a random compliment."""

    player = request.args.get('person')
    nice_thing = choice(COMPLIMENTS)

    return f"""
    <!doctype html>
    <html>
    <head>
      <title>A Compliment</title>
    </head>
    <body>
      Hi {player} I think you're {nice_thing}!
    </body>
    </html>
    """

What’s inside a request?

from flask import Flask, request

# (...snippet)

@app.route('/my/route')
def my_route():
    """Get stuff from form."""

    value = request.args.get('my-field-name')

Different Types of Requests

  • GET Requests

    • no side effects

    • For example, view an airline’s homepage, search for flights

  • POST Requests

    • there are side effects

    • For example, submit an order for airplane tickets

    • What’s the side effect?

      • Charge a credit card

GET Requests

The GET method is implied by default an HTML form…

<form action="/greet">

is the same as specifying:

<form action="/greet" method="GET">

...and the GET method is implied by default in the route

@app.route('/greet')

is the same as specifying:

@app.route('/greet', methods=['GET'])

To use the form data in your route you will need request.args:

player = request.args.get('person')

POST Requests

To use the POST method, it needs to be specified in both places.

  • In HTML, specify that when the form submits, it will send a POST request:

    <form action="/greet" method="POST">
    
  • In Flask, specify that the receiving route will accept a POST request:

    @app.route('/greet', methods=['POST'])
    

To use the form data in your route you will need request.form:

player = request.form.get('lastname')

Choosing a method

There are reasons to use either method, but the method must match between the form action and the app.route or you will get errors. Also note the syntax difference between the HTML “method” and the route “methods”. There are ways to make your route handle GET and POST at the same time, which is why even when you’re using only one method, it’s in a list and the variable is plural.

A key difference is that request.args.get() is for finding GET parameters; for POST parameters, use request.form.get().

Complete Example

Setup

$ hbget flask-intro
$ cd ~/src/flask-intro
$ virtualenv env
$ source env/bin/activate
(env) $ pip3 install flask

server.py

from flask import Flask, request
from random import choice, randint


COMPLIMENTS = ['smart', 'clever', 'tenacious', 'awesome', 'Pythonic']

app = Flask(__name__)
@app.route('/')
def index():
    """Show homepage"""

    return """
    <html>
    <body>
      <h1>I am the landing page</h1>
    </body>
    </html>
    """
@app.route('/form')
def show_form():
    """Greet user and ask for name."""

    return """
    <!doctype html>
    <html>
    <head>
      <title>Hi There!</title>
    </head>
    <body>
      <h1>Hi There!</h1>
      <form action="/greet">
        What's your name?
        <input type="text" name="person">
        <input type="submit">
      </form>
    </body>
    </html>
    """
@app.route('/greet')
def offer_greeting():
    """Greet user with a random compliment."""

    player = request.args.get('person')
    nice_thing = choice(COMPLIMENTS)

    return f"""
    <!doctype html>
    <html>
    <head>
      <title>A Compliment</title>
    </head>
    <body>
      Hi {player} I think you're {nice_thing}!
    </body>
    </html>
    """
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Variables in a URL

Motivation

Dynamic URLs

Argument capture in Flask:

@app.route('/user/<username>')
def show_user_profile(username):
    """Show the user profile for that user."""

    return f'Profile page for user: {username}'
  • <variable_name> in @app.route

  • must also be passed as argument to view function

  • default is string

Can also specify int variable:

@app.route('/post/<int:post_id>')
def show_post(post_id):
    """Show the post with the given id, the id is an integer."""

    return f'Blog post #{post_id}'
  • <int:variable_name> in @app.route

  • must also be passed as argument to view function

Other Web Frameworks

Complexity v Features

digraph frameworks { rankdir = BT; "SimpleHTTPServer (built-in to Python)" -> "Flask (Python), Node (JavaScript)" -> "Django (Python), Ruby on Rails (Ruby)" -> "Plone (Python)" -> "WordPress (PHP)" }

About the examples

SimpleHTTPServer is built-in to Python and focuses on single-file, very straightforward web applications. You could read the source code to the entire module in an hour.

Flask is a much more sophisticated system, but still focuses on single-file, relatively-straightforward applications. You could read the entire source of Flask in a day or two.

Node.js is a library slightly less abstract that Flask that allows a web application to be written in server-side JavaScript.

Django and is an even more sophisticated system, focusing on large, highly-scalable applications, with many “opinions” about how things should be done to leverage common patterns and allow team members to quickly join and acclimate themselves. It would take a week or two to read all of the source code for Django.

Ruby on Rails is similar to Django in the amount of scaffolding it provides for how a web application should be laid out, and where functionality should belong. However, it’s for the Ruby programming language.

Plone and Wordpress are the most complex and sophisticated of these, having lots of user-facing features build in a huge ecosystem of add-ons. Systems this large aren’t designed for someone to read all the code, but have extensive plug-in points to change the behavior — but if you did sit down to read it all, this might take months. These types of systems are often referred to as Content Management Systems or CMS.

What Is Helpful About Flask

  • Initial focus: “one file” web applications

  • Focus: simplicity, gets-out-of-your-way

  • Flexible about template languages, databases

  • Lots of add-on packages for additional functionality

  • Sweet spot: single-purpose apps, easy deployment

Looking Ahead

Coming Up

  • Templating with Flask

    • And, later, other explorations of Flask

  • flask-intro exercise

  • How the Web Works lecture

Flask Documentation