
Welcome!
Everything is fine.
Flask Part 3b
Last time, we went over the people_app
and tried to understand all
of it, before we go on to newer topics. Today, we'll make double-sure
that the people_app
is clear, and then we'll go on to those topics.
- Goal
- Plan
- Announcements
- Starting
- Copying the People App
- Running the People App
- Quiz questions
- Today's Examples
- TO DO
- Example: request_method (sqrt)
- Redirects
- Flashing
- Example of Flashing
- Breakout Exploration
- Breakout Exercise: People Born in Month
- Part 1 the Form
- Part 2 Processing the Form
- Part 3 Redirect
- Part 4 Flashing
- Summary
Goal¶
By the end of today, you will be able to use redirects and flashing in Flask applications. You'll be completely prepared for H6 Lookup and almost prepared for H7 CRUD.
Plan¶
- Announcements:
- your questions
- Forms in Flask: the
request
object - redirects
- flashing
- Breakout: form to specify the birth month for search
Announcements¶
- Happy International Women's Day!
- I'll grade P2 (design and plan) and H4 (ER) ASAP. Don't wait for me
- I made two mistakes on the Quiz: Q3 had the wrong answer designated as the correct one, and Q7 had zero points. Almost everyone got both questions right. I'm sorry for my errors.
- Most people feeling better about People App, though there are still a lot of people who are undecided or didn't respond. How can I help?
Starting¶
To start our work for today, make sure you activate your virtual environment:
source ~/cs304/venv/bin/activate
Copying the People App¶
If you didn't do so last week, now is the time to make sure you have a copy of the People app.
cd ~/cs304/
cp -r ~cs304/pub/downloads/people_app people_app
cd people_app
Running the People App¶
Run the app:
python app.py
VS Code should start up an SSH tunnel automatically, so you should be able to just click on the link.
I'll demo and you'll try this too:
- /
- /people/
- /people-born-in/9
- edit the url to try a different month
Quiz questions¶
This is a good time to answer your quiz questions.
Today's Examples¶
Copy the flask3
folder from the course account to your own, and you can
re-create all of today's examples:
cd ~/cs304/
cp -r ~cs304/pub/downloads/flask3 flask3
Guide: That folder has these files. We'll do what we can, leaving some for tomorrow.
all_examples.py
defines theapp
object, and imports the examples. So, we run it, but read the code in other files.example_request_method.py
is our first form example, showing different request methods.example_form_processing_one_route.py
is our second form example, showing GET to get an empty form and POST to use it.example_post_redirect_get.py
is our third form example, showing POST that redirects to a GET route to do the real work.example_flashing.py
is an example of flashing to report errors in an easy way.
TO DO¶
I will run the all_examples.py
app in the guest account. You're welcome
to do the same with your copy. We'll look at the code using VSC.
Example: request_method (sqrt)¶
As you know, forms are critically important in Web applications. Our
first example is example_request_method.py
, which also refers to
templates/sqrt_form.html
and templates/msg.html
.
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>{{title}}</title>
</head>
<body>
<h2>GET</h2>
<form method="GET" action="{{processor}}">
<p><label>input number
<input name="num" type="number" step="any">
</label></p>
<p><input type="submit" value="GET"></p>
</form>
<h2>POST</h2>
<form method="POST" action="{{processor}}">
<p><label>input number
<input name="num" type="number" step="any">
</label></p>
<p><input type="submit" value="POST"></p>
</form>
<h2>Menu</h2>
<form method="GET" action="{{processor}}">
<p><label>select number
<select name="num">
<option value="2">two</option>
<option value="3">three</option>
<option value="3.1416">pi</option>
<option value="4">four</option>
</select>
</label></p>
<p><input type="submit" value="submit"></p>
</form>
</body>
</html>
Notice:
- There can be more than one form on a page
- They can have different methods. Note the difference in how the data is sent.
- Notice the different behavior on re-submission. (Click the reload button.)
- the ACTION needs to be filled in. Typically I put this in the template, rather than in the route.
- How to use a SELECT menu
- We could use
url_for(...)
in the template, where we have{{processor}}
if it'll always go to the same place, which is typical. I separated them to make the Python code clearer, but it's usually better to put theurl_for()
in the template.
Here is the Flask code to process it:
from flask import (Flask, url_for, render_template, request,
redirect, flash)
import math
from all_examples import app
@app.route('/sqrt_form/')
def sqrt_form():
# This route just returns the form.
return render_template('sqrt_form.html',
processor=url_for('compute_sqrt'))
@app.route('/compute_sqrt/', methods=['GET','POST'])
def compute_sqrt():
# the request object is a new import from flask
if request.method == 'GET':
num = request.args.get('num')
else:
num = request.form.get('num')
try:
x = float(num)
y = math.sqrt(x)
return render_template(
'msg.html',
msg=('Square root of {x} is {y}'
.format(x=x,y=y)))
except:
return render_template(
'msg.html',
msg=('Error computing square root of {num}'
.format(num=num)))
- The
request
symbol needs to be imported request.method
is either GET or POSTrequest.args
goes with GETrequest.form
goes with POST- Look at the URL with the different options
Redirects¶
A redirect is a short response to the browser telling it to make a different request. You can say
- 301 moved permanently
- 302 found (temporarily)
- Many others. Check HTTP Status Codes
Redirects can be used for a variety of reasons.
- To clean up a URL using query parameters, converting:
/find?q=123
to/name/nm123
- To transfer someone to a more appropriate page:
/login?name=fred&pass=ok
/user/fred
You don't want to over-use redirects. It should be more about what the user sees rather than convenient coding.
As with render_template()
you return
the redirect:
return redirect( url_for('index') )
Also, you have to import the redirect
function; see below.
Flashing¶
A web application should always let the user understand what's going on:
- Confirmation of updates
- Show search criteria as well as search results
- Appropriate error messages
You can do this by inserting information on the page:
{% if errmsg %}
<p>{{ errmsg }}</p>
{% endif %}
A more general solution is to have a collection of messages that you can iterate over to show them all. Like this:
{% with messages = get_flashed_messages() %}
{% if messages %}
<div id="messages">
{% for msg in messages %}
<p>{{msg}}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
How you format the messages, of course, is up to you. Here, we've used a bunch of paragraphs in a DIV. Style it with CSS.
To add a message to the list, use the flash()
function:
flash('actor inserted')
You have to remember to import the flash
function into your app. See
below.
Flask uses a special kind of cookie to implement sessions and flashing, thereby allowing the flashed messages to go across re-directs. We'll discuss the implementation later. However, it's important to know that you have to set a secret key. For security reasons, this should be unguessable. Set it like this (globally in your app).
from flask import (Flask, render_template, make_response,
request, redirect, url_for, flash)
app = Flask(__name__)
app.secret_key = 'replace this string'
In the all_examples.py
file, we generate a random secret key each time.
Example of Flashing¶
The example_flashing.py
file demonstrates flashing.
Here are the Flask routes:
from flask import (Flask, url_for, render_template, request,
redirect, flash)
import math
from all_examples import app
@app.route('/log2/', methods=['GET','POST'])
def log2():
if request.method == 'GET':
# this gets the blank form by visiting the URL
return render_template('log2.html')
else:
if request.form.get('num') is None:
flash('No "num" in the request')
return render_template('log2.html')
num = request.form.get('num')
try:
x = float(num)
except:
flash('Could not convert {} to float'.format(num))
return render_template('log2.html')
if x == 0:
flash('Definitely cannot compute log of zero.')
return render_template('log2.html')
if x < 0:
flash('''Cannot compute log of negative;
using absolute value instead''')
x = abs(x)
# finally!
y = math.log(x,2.0)
return render_template('log2.html',x=x,y=y)
Breakout Exploration¶
Spend some time exploring the examples. Here's how to run them:
cd flask3
python all_examples.py
Discussion/experiments:
- change the URL for the the route in
...one_route.py
from/ln/
to/natural-log/
. What other things have to change? - add a city in the
post_redirect_get
example. - should we use POST for this kind of form?
Breakout Exercise: People Born in Month¶
Your flask3
folder has a subfolder pa1
which has a copy of the
people_app
with a few extras in it.
Your goal is to add a page with a form that allows the user to request a list by the birthmonth they specify:
You'll also process that form input and respond with the correct list
Part 1 the Form¶
- add a route that sends the empty form to the user. This only needs to be a simple route that renders the template and returns it.
- test that; you'll have to type in the URL
- add a hyperlink to the main page that goes to the correct URL
- test that
Part 2 Processing the Form¶
- add a route that will process the submitted form.
It's just vacous for now. Return a boring page, like
hello_world
- modify the form to send the data to that route
- modify the route to print the submitted form input to the console.
You'll have to import the
request
object. - test that
- convert the value to an int
- Replace the vacuous response with a real response. You can copy/paste the code from earlier in the file (though copy/paste is usually a bad sign). We'll fix this soon.
- test that
Part 3 Redirect¶
- Instead of the copy/pasted code, return a
redirect
to the correct route You'll have to importredirect
- test that
Part 4 Flashing¶
- Import
flash
from Flask - set the
secret_key
attribute of theapp
object. - flash the same message as you printed
- add the flashed messages incantation to your templates. See below
- test this
The flash incantation is something like this. You can modify the HTML, such as using OL and LI instead of DIV and P.
{% with messages = get_flashed_messages() %}
{% if messages %}
<div id="messages">
{% for msg in messages %}
<p>{{msg}}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
Summary¶
You know about
- forms
- request methods
- redirects
- flashing