Assignments > Lab 2. Setting Up Python & Flask
Due on Fri, 04/08 @ 11:59PM. 5 Points.
1. Intro to Flask
Flask is a framework, built with Python, for helping people build dynamic, scalable web applications. We have selected Flask as our web server engine for this quarter because it has a relatively simple set of common abstractions, and is therefore easier to learn than some other frameworks. At the same time, it is also very powerful, and has features such as:
- Templating, using the Jinja template engine
- A simple way to define routes (which bind URL addresses to functions), and to specify which HTTP methods are valid for a particular route (HEAD, OPTIONS, GET, POST, PUT, PATCH, DELETE)
- A way to listen for and parse HTTP requests over a specified port
- A way to create and send HTTP responses
In addition, since Flask is written in Python, you have access to any and all Python libraries (e.g., for connecting to various databases, taking advantage of pretrained models, and so forth).
Most frameworks have abstractions similar to those offered by Flask, so once you learn Flask, learning new server-side web frameworks will be easier. Some other web frameworks that are analagous to Flask (that you may have heard of) include:
Python | Flask, Django, Web2Py, Pyramid, etc. |
Node.js | Express, etc. |
PHP | Larvel, Symfony, etc. |
Ruby | Rails, etc. |
Java | Spring, Struts, etc. |
C# | ASP.NET |
2. Intro to Python Virtual Environments
From the Python Docs:
A virtual environment is a Python environment such that the Python interpreter, libraries and scripts installed into it are isolated from those installed in other virtual environments, and (by default) any libraries installed in a “system” Python, i.e., one which is installed as part of your operating system.
Practically speaking, a virtual environment (venv) “sandboxes” your Python installation so that anything installed within a venv is not available outside of it. Libraries installed in a “system” Python ARE available to your venv, but can be overridden from within the venv. For instance, if numpy version 1.15.4
is installed on your “system” Python and you decide to install numpy version 1.16.1
in your venv, then within the venv, 1.16.1
will take precedence.
Some commands to know:
python3 -m venv env # creates a new virtual environment called "env"
source env/bin/activate # activates the virtual environment (stored in the "env/bin" folder)
deactive # deactivates the virtual environment
Note that when your venv is activated, there will be a (env)
prefix in front of your command prompt. When activated, any python or pip install
commands will be interacting with your virtual environment.
3. Background Readings
Please read the following:
- Janetakis, Nick (Oct., 2017). Server Side Templates vs REST API and Javascript Front-End.
- Flask website. Flask Quickstart Guide
- Towards Data Science. Intro to Python Virtual Environments
4. Set Up
If you haven’t used Python before, please download and install it: https://www.python.org/downloads/. Any version of python >= 3.7 will work.
Once Python is installed, download lab02.zip (below), unzip it, and move your lab02 folder inside of your webdev-labs folder.
Your directory structure should look like this. Note that your git repository should be in the root of your webdev-labs directory:
webdev-labs
├── .git
├── lab01
│ ├── exercise01
│ └── exercise02
└── lab02
├── .gitignore
├── Procfile
├── app.py
├── helpers
├── requirements.txt
├── static
└── templates
Set Up Your Virtual Environment
Open the terminal and navigate to your lab02 folder. Then, set up a virtual environment and install the dependencies as follows (depending on your operating system):
For Mac, Unix, Linux, or GitBash
python3 -m venv env
source env/bin/activate
pip install -r requirements.txt # install dependencies
For Windows Powershell or Command Prompt
# create the virtual environment
py -m venv env
# run the activate.bat script as follows:
env\Scripts\activate
# and finally, install the Python dependencies
py -m pip install -r requirements.txt
Run Your Flask Web Server
When you’re done, try running your flask app from your command line:
Mac or Linux
# set environment variables (you just have to do this once per session)
export FLASK_APP=app.py
export FLASK_ENV=development
# then run flask (type Ctrl+C to quit)
flask run
Windows Command Prompt
# set environment variables (you just have to do this once per session)
set FLASK_APP=app.py
set FLASK_ENV=development
# then run flask (type Ctrl+C to quit)
flask run
# alternative commands to try if "flask run" doesn't work:
# py -m flask run
# python3 -m flask run
# python -m flask run
Powershell
$env:FLASK_APP="app.py"
$env:FLASK_ENV="development"
flask run
You should see the following output:
* Serving Flask app "app.py" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 273-580-071
Navigate to http://127.0.0.1:5000/, and you should see a screen that says “Hello World!”
FAQs / Troubleshooting
Sarah will keep adding FAQs to this section. Some known issues:
- If
python3
orpy
aren’t recognized, ask your peer mentor / go to office hours. It is important that you figure out how to invoke python from the command line ASAP, as you’ll need to do this for the rest of the quarter. - If you are using windows and you can’t start flask using the
flask run
command, try:python -m flask run
5. Required Flask Exercises
Once you’ve set up your flask installation, you will do 4 required exercises:
Exercise | Purpose | |
---|---|---|
1. | Display personalized greeting | Practice generating and sending a dynamic string via HTTP |
2. | Create a template | Practice creating a data-driven, server-side HTML file from a template. Templates allow you to separate the data from the presentation of the data. |
3. | Accessing data from other servers | Practice retrieving data from another server using query parameters. |
4. | Create a data-driven template | Practice retrieving data from another server and sending it to a client. |
Please complete the following exercises to get a sense of the kinds of things you can do with Flask:
1. Display personalized greeting
Update the exercise1
function so that it returns a personalized greeting to the user. In other words, replace “Hello World!” with something like, “Hi Erick!”
- Assume that the
current_user
variable, defined at the top ofapp.py
represents the user who is currently logged in.
2. Merge with a template
The exercise2
function uses a template to generate its response. Specifically, python reads in the templates/quote-of-the-day.html
file, finds any python expressions (represented by curly braces), evaluates them, and finally sends a “plain” HTML file back to the client:
@app.route('/quote')
def exercise2():
return render_template(
'quote-of-the-day.html',
user=current_user
)
Open the templates/quote-of-the-day.html
file and examine how the Jinja template allows python logic to be evaluated from within the HTML template (using double curly brace notation). Note that in order to give your template access to data, it must be passed into the render_template
function as a keyword argument (from app.py
). You may pass in as many keyword arguments (i.e. pieces of data) as you like into the template. These pieces of data are often referred to as the template’s “context.”
Your Task
Please make the following modifications:
- In
app.py
, add another context variable, calledquote
that holds a randomly selected quote from thequotes
list (see ~line 17). Consider using the built-in random.choice function. - In
templates/quote-of-the-day.html
, update the template so that the quote of the day is displayed.
3. Accessing data from other servers
Servers can also be clients that issue requests to other servers (the thing doing the “asking” is usually referred to as the client). In other words, your Flask server can query data from other servers (using HTTP or other protocols) and then make use of that data in their own way. The exercise3
function queries a proxy server that Sarah made (https://www.apitutor.org) for accessing Yelp (and other providers). In this example, we are querying Yelp for restaurants that match a location and search term:
@app.route('/restaurant-data')
def exercise3():
search_term = 'pizza'
location = 'Evanston, Il'
url = 'https://www.apitutor.org/yelp/simple/v3/businesses/search?location={0}&term={1}'.format(location, search_term)
response = requests.get(url)
data = response.json()
pprint(data) # for debugging -- prints the result to the command line
return json.dumps(data)
Note that the /restaurant-data
route returns a JSON string (instead of an HTML string).
Your Task
You are going to make this route more customizable by replacing the code shown above with this code:
@app.route('/restaurant-data/')
@app.route('/restaurant-data')
def exercise3():
args = request.args
location = args.get('location')
search_term = args.get('term')
if not (location and search_term):
return '"location" and "term" are required query parameters'
url = 'https://www.apitutor.org/yelp/simple/v3/businesses/search?location={0}&term={1}'.format(location, search_term)
response = requests.get(url)
data = response.json()
pprint(data) # for debugging -- prints the result to the command line
return json.dumps(data)
The code above allows the user to specify the location and search term they’d like to use when querying yelp using “query parameters.” Here is an example of a URL that uses query parameters:
http://127.0.0.1:5000/restaurant-data/?location=Evanston+IL&term=chinese
- The
?
character is used to specify where the route ends and the query parameters begin. - If there is more than one query parameter, then each parameter/argument pair is separated by an
&
character (see examples below). - The parameter name is on the left side of the
=
and the value is on the right side. - In flask, you can access the query parameters via the
request.args
, which stores a dictionary representation of any query parameters associated with a given route.
After making the changes above, test your new routes by experimenting with the following URLs:
- http://127.0.0.1:5000/restaurant-data/?location=Evanston+IL&term=chinese (Chinese restaurants in Evanston)
- http://127.0.0.1:5000/restaurant-data/?location=San Diego,%20CA&term=thai (Thai restaurants in San Diego)
Feel free to replace the cities and search terms with your own! Basic takeaway: you can allow your user to pass arguments to your routes via query parameters.
4. Create a data-driven template
Now, you’re going to create a data-driven template to display information about the “Top Restaurant” (according to Yelp) that matches your search criteria. Consider the following code:
@app.route('/restaurant/')
@app.route('/restaurant')
def exercise4():
args = request.args
location = args.get('location')
search_term = args.get('term')
if not (location and search_term):
return '"location" and "term" are required query parameters'
url = 'https://www.apitutor.org/yelp/simple/v3/businesses/search?location={0}&term={1}'.format(location, search_term)
response = requests.get(url)
restaurants = response.json()
pprint(restaurants[0]) # for debugging
return render_template(
'restaurant.html',
user=current_user,
search_term=search_term,
location=location,
restaurant=restaurants[0] # just show the first restaurant in the list.
)
It works very similarly to the code in exercise 3, except for it merges with the restaurant.html
template (instead of dumping raw JSON data). Please try testing these routes by experimenting with the following URLs:
- http://127.0.0.1:5000/restaurant/?location=Evanston,%20IL&term=chinese (Chinese restaurants in Evanston)
- http://127.0.0.1:5000/restaurant/?location=San Diego,%20CA/thai (Thai restaurants in San Diego)
Note that the restaurant.html
template uses a new construct – the “include” – as a way to modularize code.
Your Task
Modify the HTML in this template so that it displays the Yelp data in a more visual format. For instance, Sarah made her’s look like this:
Feel free to jazz up your template any way you like!
6. Optional Flask Exercises (recommended if time)
If you have more time, please also try the optional flask exercises. It will give you more practice to ensure that you feel comfortable with HW2!
1. Looping using Jinja
In exercise 4, you only showed a single restaurant. Look at the Jinja documentation and see if you can figure out how to output all of the matching restaurants for the search (not just the first one). See if you can make your template look like this one:
2. Includes
See if you can convert the HTML that shows a single restaurant card into an include file (similar to includes/header.html
)
7. What to Turn In
To submit Lab 2:
1. Push all of your files to GitHub
Please copy the latest version of your files to GitHub by issuing the following commands:
git status # shows you what has been changed and which files are being tracked
git add . # stage your changes to be committed
git commit -m 'Commiting my completed lab02 files'
git push # sends your files to GitHub
2. Paste a link to your repo on Canvas
Paste a link to your webdev-labs
GitHub repository into the Canvas textbox for Lab 2.