CIS 192: Lecture 10
Web Development with Flask
Lili Dworkin University of Pennsylvania
Web Frameworks
I We’ve been talking about making HTTP requests
I What about serving them?
I Flask is a “microframework” – small and simple, and you can see how and why everything is happening
I Django is the “big guy on the block” – more fully featured, but also more black magic / mysterious
Hello World
from flask import Flask app = Flask(__name__) @app.route('/')
def hello_world():
return "Hello World!" if __name__ == '__main__':
app.run()
prompt$ python flask.py
Hello World
app = Flask(__name__)
I When we create an instance of the Flask class, the first argument is the name of the application’s module or package
I When using a single module, use __name__because this will work regardless of whether __name__equals ’__main__’or the actual import name
Hello World
@app.route('/') def hello_world():
return "Hello World!"
I The app.route('/')decorator tells Flask to call the hello_world()function when the relative url ’/’ is accessed
I The hello_world()function returns the web page (in this case, a simple string) to be displayed
Hello World
app.run()
I Theapp.run() function runs the application on a local server
I This will only be visible on your own computer! We will talk about deployment later
Debugging
I When testing, use app.run(debug=True)
I Now the server will reload itself on code changes
I Additionally, you will see error messages in the browser
More Routing
@app.route('/bad') def bad(): return 'hi' + 4 @app.route('/bye') def bye_world():Variable Rules
I To add variable parts to a url, use <variable_name>
I The variables are passed as arguments to the function @app.route('/user/<username>')
def greet_user(username):
Variable Rules
Multiple urls can route to the same function: @app.route('/name/<first>')
@app.route('/name/<first>/<last>') def greet_name(first, last=None):
name = first + ' ' + last if last else first return "Hello %s!" % name
Templating
What about some real HTML?
Flask uses a templating system called Jinja. <!doctype html>
<title>Hello from Flask</title> {% if name %}
<h1>Hello {{ name }}!</h1> {% else %}
<h1>Hello World!</h1> {% endif %}
Templating
from flask import render_template @app.route('/template/')
@app.route('/template/<name>') def template(name=None):
GET Requests
I Recall: a url can be accessed with parameters, i.e. /hello?key=value
I Retrieve these parameters from the request.args dictionary from flask import request
@app.route('/args') def args():
html = ''
for key, value in request.args.items(): html += '%s=%s' % (key, value) html += '<br/>'
GET Requests
Even better, using templates: <!doctype html>
<title>Displaying Params</title> <ul>
{% for key, value in params.items() %} <li>{{ key }}={{ value }}</li>
{% endfor %} </ul>
@app.route('/template_args') def template_args():
return render_template('params.html', params= request.args)
POST Requests
I We can also make POST requests to a url
I Add keyword argument methods=['POST', 'GET']to the app.route()decorator
I Check if a request was a POST by looking at request.method
I The data from a POST request can be retrieved from the request.form dictionary
POST Requests
@app.route('/post', methods=['POST', 'GET']) def post():
if request.method == 'POST':
return request.form.get('data', 'default') else:
return 'That was a GET request.'
>>> req = requests.post('http://127.0.0.1:5000/post', data={'data':'test data'})
>>> req.text u'test data'
>>> req = requests.post('http://127.0.0.1:5000/post') >>> req.text
Returning JSON
Instead of returning HTML source, what if we want to return JSON?
from flask import jsonify @app.route('/json')
def return_json():
return jsonify({'some': 'data'})
>>> req = requests.get('http://127.0.0.1:5000/json') >>> req.json()
Sessions
Sometimes you need to store information between requests. For this we use the “session” object, which is essentially a cookie. from Flask import session
app.secret_key = os.urandom(24) @app.route('/step1')
def step1():
session['key'] = '12345' return 'Saved key.' @app.route('/step2') def step2():
key = session['key']
url for
What if we need to know the link for one of our functions? from Flask import url_for
@app.route('/url') def url():
html = 'relative url: %s <br/>' % (url_for('bye_world'))
html += 'absolute url: %s' %
(url_for('bye_world', _external=True)) return html
Back to Twitter
Let’s recall the 3-legged OAuth process:
1. Get a request token
2. Send user to an authorization url
3. Redirect user back to application with their pin/verifier
4. Get an access token
Back to Twitter
Getting request/access tokens is a little tricky – we need to:
1. Put together the consumer/key secret (use oauth.Consumer)
2. For the access token only: Put together the request token key/secret (use oauth.Token)
3. Put our params in a dictionary
I For the request token, this is{oauth_callback: ...} I For the access token, this is{oauth_verifier: ...}
4. Make a signed request (use oauth.Request)
5. POST to the signed url
6. Parse the body of the response for the key and secret I The response body will be of the form
Back to Twitter
Posting the status update is pretty similar:
1. Put together the consumer/key secret (use oauth.Consumer)
2. Put together the access token key/secret (use oauth.Token)
3. Put our params in a dictionary: {status: ...}
4. Make a signed request (use oauth.Request)