
Welcome!
Everything is fine.
Flask Part 2: Templates¶
Today, we'll continue to work with Flask and start to learn Templating
Goal¶
By the end of today, you will be able to debug Flask applications, build URLs, and use templating. You'll be ready for both the Forms assignment and even the Lookup assignment.
Plan¶
- Announcements
- PyMySQL continued:
- Prepared Queries
- SQL injection
- Breakout: Pet Lookup v2
New Material
- Templating
- Quiz Questions
- Breakout
Announcements¶
- Grading status
- Please create project teams by tomorrow.
- Heavy reading next, but not a lot of new material
people_app
puts all the pieces together- students like it
Breakout: Pet Lookup v2¶
To get my solution working, you'll need the owner9
and pet9
tables. Here's how to do that:
First, get the mysql5-refinteg
materials, if you don't already have
them. You can copy/paste each of these blocks into your
terminal. There's a "copy" button in the upper right.
cd ~/cs304
cp -r ~cs304flask/pub/downloads/mysql5-refinteg .
Then, you'll need to source those two files:
cd ~/cs304/mysql5-refinteg
mysql < vet-setup.sql
mysql < vet-data.sql
Then, go back to your pymysql
folder and run the example:
cd ~/cs304
source venv/bin/activate
cd pymysql
python petLookup_solution.py snow
python petLookup_solution.py crook
python petLookup_solution.py a
- Modify the solution to print the owner's name as well.
- Modify the solution to sort the results by pet's name
Code versus Data¶
It's reasonable to have trouble understanding prepared queries, because you've never dealt with code that runs code before. I also think there's a confusion about CODE versus DATA.
How many "if" statements in the following Python function?
def foo(x,y):
if len(x) > 3:
return 'if y < 2'
else:
return 'if y > 2'
How about the following function invocation?
foo('if',4)
Will the following function get a divide by zero error?
def bar():
y = 4
z = '1/0'
return y+z
(It will get an error for concatenating a number and a string.)
In the cases above, there is Python "code" in strings, but they will never get executed. They are not treated as code.
Questions on Prepared Queries¶
I'll answer your questions on prepared queries
Reminder: How to Run a Flask App¶
- Activate your virtual environment:
source ~/cs304/venv/bin/activate
- Navigate to the folder with your app (the one with
app.py
) - Run
app.py
using Python:python app.py
- Click on the given URL to go to your browser. Something like
http://127.0.0.1:wxyz/
where thewxyz
is your four-digit UID/PORT.
Using URL_FOR¶
If you have the following in your app.py
@app.route('/foo/'):
def do_foo():
render_template(...)
It will be very tempting to link to that by using the URL:
<a href="/foo/">this will run do_foo()</a>
and that will work.
However, if you ever want to deploy your app, you would have to add a prefix to the urls, and that will involve a lot of tedious and error prone editing of the code. And then you've messed up your development version.
Instead, do the following:
<a href="{{ url_for('do_foo') }}">this will run do_foo()</a>
Summary:
- Use
url_for
anytime you need to write a URL from your app. It's cumbersome, but important. - in templates, in hyperlinks, in redirects (later), etc.
- we will see lots of examples today
Static Files¶
We can deliver static files (CSS, JS, images) by
- putting them in a
static
folder (or any other name) and - using
url_for('static', filename = some_value)
For example, in an HTML template:
<html>
<head>
...
<link rel='stylesheet'
href="{{url_for('static', filename = 'style.css')}}">
...
</html>
This example is from flask-starter
.
The REQUEST Object¶
- Flask creates an object storing information about the request
- Flask puts the object in a "global" variable called
request
- we must
import
that variable from Flask (add it to ourimport
statement) - The
app.py
inflask-starter
does that for us. - The
request
object has amethod
property that has values likeGET
andPOST
- It also has:
request.form
holds form data from a POST requestrequest.args
holds form data from a GET request
- We list the request methods that a given endpoint handles. Default is just GET
Quiz Questions¶
Most people were in the middle on this reading. Let's answer some questions first.
I'll answer your quiz questions
Today's Examples¶
Go to your cs304
folder and copy the examples for today:
cd ~/cs304
cp -r ~cs304flask/pub/downloads/flask2 flask2
Country Database¶
First, let's look at country_db.py
Open up a Python REPL and play with it:
import country_db as db
db.country_lookup_by_name_tuple('France')
db.country_lookup_by_name_dicts('China')
db.insert_country('Italy', 'Rome', 'Europe')
db.insert_country('Spain', 'Madrid', 'Europe')
Running The Examples¶
The Flask example example4.py
code is
example4.py. We'll refer back to that as often as
necessary.
- I'll show the home page first. We'll talk about using
url_for
. - The detail page for France. We'll walk through all that code.
- iterating over a list of dictionaries
- getting some data as a tuple and rendering a template using the data
- getting some data as a dictionary and rendering a template using the data
- getting a list of results and rendering them
- sending a blank GET form to the browser.
- an endpoint that lacks a query string
- sending a blank POST form to the browser
- a template that uses a (static) CSS file
Template Files¶
Do "view source" (command-u) to see the template code.
hello.html
country.html
the data is a bunch of separate valuescountry-dic.html
the data is a dictionarycountry-lookup-form.html
a template with a GET formnew-country-form.html
a template with a POST form
Exercise¶
Practice with Flask and Jinja2 by doing the following.
Create a web app to display information about Fred Weasley.
You can find starter code in the fred_ex
folder.
- make the link work to the fred route
- the fred page should look like this:
To do that, you'll need to
- modify the template file to provide places to fill in the data, and
- modify the
app.py
file to fill the data in
Summary¶
You know about
- url_for
- URL patterns
- templates
- static files