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

  1. Announcements
  2. PyMySQL continued:
    • Prepared Queries
    • SQL injection
  3. Breakout: Pet Lookup v2

New Material

  1. Templating
  2. Quiz Questions
  3. Breakout

Announcements

  1. Grading status
  2. Please create project teams by tomorrow.
  3. 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

  1. Modify the solution to print the owner's name as well.
  2. 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

  1. Activate your virtual environment: source ~/cs304/venv/bin/activate
  2. Navigate to the folder with your app (the one with app.py)
  3. Run app.py using Python: python app.py
  4. Click on the given URL to go to your browser. Something like http://127.0.0.1:wxyz/ where the wxyz 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 our import statement)
  • The app.py in flask-starter does that for us.
  • The request object has a method property that has values like GET and POST
  • It also has:
    • request.form holds form data from a POST request
    • request.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.

  1. I'll show the home page first. We'll talk about using url_for.
  2. The detail page for France. We'll walk through all that code.
  3. iterating over a list of dictionaries
  4. getting some data as a tuple and rendering a template using the data
  5. getting some data as a dictionary and rendering a template using the data
  6. getting a list of results and rendering them
  7. sending a blank GET form to the browser.
  8. an endpoint that lacks a query string
  9. sending a blank POST form to the browser
  10. a template that uses a (static) CSS file

Template Files

Do "view source" (command-u) to see the template code.

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:

page about fred

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