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.
The server then responds with HTML text for that page:
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.
from random import choice, randint
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¶
@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¶
Want to show info about a user with username balloonicorn at http://localhost:5000/user/balloonicorn
We don’t want every possible username as a separate route
Want to show blog post with id 1 at http://localhost:5000/post/1
Example: Amazon
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¶
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¶
The Flask documentation (http://flask.pocoo.org/)