CIS 192: Lecture 10 Web Development with Flask Lili Dworkin University of Pennsylvania
Web Frameworks We ve been talking about making HTTP requests What about serving them? Flask is a microframework small and simple, and you can see how and why everything is happening 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 * Running on http://127.0.0.1:5000/
Hello World app = Flask( name ) When we create an instance of the Flask class, the first argument is the name of the application s module or package 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!" The app.route('/') decorator tells Flask to call the hello_world() function when the relative url / is accessed The hello_world() function returns the web page (in this case, a simple string) to be displayed
Hello World app.run() The app.run() function runs the application on a local server This will only be visible on your own computer! We will talk about deployment later
Debugging When testing, use app.run(debug=true) Now the server will reload itself on code changes Additionally, you will see error messages in the browser But never leave this on in production!
More Routing @app.route('/bad') def bad(): return 'hi' + 4 @app.route('/bye') def bye_world(): return "Bye World!"
Variable Rules To add variable parts to a url, use <variable_name> The variables are passed as arguments to the function @app.route('/user/<username>') def greet_user(username): return "Hello %s!" % 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 %} Need to put this in a templates folder.
Templating from flask import render_template @app.route('/template/') @app.route('/template/<name>') def template(name=none): return render_template('index.html', name=name)
GET Requests Recall: a url can be accessed with parameters, i.e. /hello?key=value 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/>' return html
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 We can also make POST requests to a url Add keyword argument methods=['post', 'GET'] to the app.route() decorator Check if a request was a POST by looking at request.method 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 u'default'
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() {u'some': u'data'}
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'] return 'Retrieved key: %s.' % (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 5. Post to Lili s Twitter account
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 For the request token, this is {oauth_callback:...} 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 The response body will be of the form oauth token=xxx&oauth token secret=xxx
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) 5. POST to the signed url