Python Web Flask
Python Web Flask
Armin Ronacher
@mitsuhiko lucumr.pocoo.org
What is it?
fun
oriented object
dynamic
functional
.py
community focused
ped ly ty rong st
widely used
Why?
Platforms? all*
*Win32, OS X, Linux, BSD, Symbian, Android
License? BSD-ish
Price? Free
.86 - - [20/Nov/2011:01:10:35 +0100] "GET /feed.atom HTTP/1.0" 200 25965 3.147 - - [20/Nov/2011:01:10:49 +0100] "GET /feed.atom HTTP/1.1" 304 153 3.35 - - [20/Nov/2011:01:10:50 +0100] "GET /2008/1/23/no HTTP/1.0" 404 4 6.211 - - [20/Nov/2011:01:10:50 +0100] "GET /feed.atom?_qt=data HTTP/1.1
import re
with open('/var/log/apache2/access.log') as f: for line in f: match = re.search(r' "\w+ (.*?) HTTP/', line) if match is None: continue print match.group(1).split('?')[0]
import re from collections import defaultdict counts = defaultdict(int) with open('/var/log/apache2/access.log') as f: for line in f: match = re.search(r' "\w+ (.*?) HTTP/', line) if match is None: continue counts[match.group(1).split('?')[0]] += 1
import re from collections import defaultdict counts = defaultdict(int) with open('/var/log/apache2/access.log') as f: for line in f: match = re.search(r' "\w+ (.*?) HTTP/', line) if match is None: continue counts[match.group(1).split('?')[0]] += 1 for url, count in counts.items(): print '%s (%d times)' % (url, count)
import re from collections import defaultdict from heapq import nlargest counts = defaultdict(int) with open('/var/log/apache2/access.log') as f: for line in f: match = re.search(r' "\w+ (.*?) HTTP/', line) if match is None: continue counts[match.group(1).split('?')[0]] += 1 most_common = nlargest(5, counts.items(), key=lambda x: x[1]) for url, count in most_common: print '%s (%d times)' % (url, count)
import re from collections import defaultdict from heapq import nlargest counts = defaultdict(int) with open('/var/log/apache2/access.log') as f: for line in f: match = re.search(r' "\w+ (.*?) HTTP/', line) if match is None: continue counts[match.group(1).split('?')[0]] += 1 most_common = nlargest(5, counts.items(), key=lambda x: x[1]) for url, count in most_common: print '%s (%d times)' % (url, count)
class LogParser { public static void main(String[] args) { try { String filename = "/var/log/apache2/access.log"; FileInputStream fstream = new FileInputStream(filename); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); Map<String, Integer> counts = new HashMap<String, Integer>(); try { Pattern pattern = Pattern.compile(" \"\\w+ (.*?) HTTP/"); String line; while ((line = br.readLine()) != null) { Matcher m = p.matcher(line); if (!m.find()) continue; String url = m.group(0).split("\\?")[0]; if (counts.containsKey(url)) counts.put(url, counts.get(url) + 1); else counts.put(url, 1); } } finally { fstream.close(); } Map.Entry<String, Integer> items[] = counts.entrySet().toArray(); items.sort(new Comparator() { int compareTo(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) { return b.getValue().compareTo(a.getValue()); } }); for (int i = 0; i < Math.min(5, items.length); i++) { Map.Entry<String, Integer> item = items[i]; System.out.println(item.getKey() + " (" + item.getValue() + " times)"); } } catch (Exception e) { e.printStackTrace(); } } }
Productivity++
To The Web
The Frameworks
Django Flask Pyramid Zope/Plone
The Stack
CSS
JavaScript
HTML
Browser
HTTP
Your App
Web Server
Python
WSGI
Framework
Y U NO SIMPLE?
Flask
http://flask.pocoo.org/
$ sudo apt-get install python-virtualenv $ sudo easy_install virtualenv For windows: http://bit.ly/easy-install-windows
Step 4 Run!
What we like:
Develop locally Isolated environments Persistent execution Automatic code reloading Kick-ass debugging Logic / UI separation
If it crashes
Pastebin
Step 0 Overview
General Purpose Pastebin Users can sign in with Facebook Authenticated users can delete their entries Authenticated users can list their entries Flask, Flask-OAuth, Flask-SQLAlchemy
Step 0 Overview
/pastebin /static /style.css /templates /layout.html /new_paste.html /delete_paste.html /my_pastes.html /pastebin.py Project Folder Static Files Templates
The Application
Step 2 Imports
from datetime import datetime from flask import Flask, request, url_for, redirect, g, session, \ abort, render_template from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.oauth import OAuth
Step 2 Imports
from datetime import datetime from flask import Flask, request, url_for, redirect, g, session, \ abort, render_template from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.oauth import OAuth
Step 2 Imports
from datetime import datetime from flask import Flask, request, url_for, redirect, g, session, \ abort, render_template from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.oauth import OAuth
Step 2 Imports
from datetime import datetime from flask import Flask, request, url_for, redirect, g, session, \ abort, render_template from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.oauth import OAuth
Step 3 Setup
app = Flask(__name__) app.config.update( SQLALCHEMY_DATABASE_URI='sqlite:///pastebin.db', SECRET_KEY='development-key' ) db = SQLAlchemy(app) oauth = OAuth() facebook = oauth.remote_app('facebook', base_url='https://graph.facebook.com/', request_token_url=None, access_token_url='/oauth/access_token', authorize_url='https://www.facebook.com/dialog/oauth', consumer_key='<consumer key here>', consumer_secret='<consumer secret here>', request_token_params={'scope': 'email'} )
Step 3 Setup
app = Flask(__name__) app.config.update( SQLALCHEMY_DATABASE_URI='sqlite:///pastebin.db', SECRET_KEY='development-key' ) db = SQLAlchemy(app) oauth = OAuth() facebook = oauth.remote_app('facebook', base_url='https://graph.facebook.com/', request_token_url=None, access_token_url='/oauth/access_token', authorize_url='https://www.facebook.com/dialog/oauth', consumer_key='<consumer key here>', consumer_secret='<consumer secret here>', request_token_params={'scope': 'email'} )
Step 3 Setup
app = Flask(__name__) app.config.update( SQLALCHEMY_DATABASE_URI='sqlite:///pastebin.db', SECRET_KEY='development-key' ) db = SQLAlchemy(app) oauth = OAuth() facebook = oauth.remote_app('facebook', base_url='https://graph.facebook.com/', request_token_url=None, access_token_url='/oauth/access_token', authorize_url='https://www.facebook.com/dialog/oauth', consumer_key='<consumer key here>', consumer_secret='<consumer secret here>', request_token_params={'scope': 'email'} )
Step 3 Setup
app = Flask(__name__) app.config.update( SQLALCHEMY_DATABASE_URI='sqlite:///pastebin.db', SECRET_KEY='development-key' ) db = SQLAlchemy(app) oauth = OAuth() facebook = oauth.remote_app('facebook', base_url='https://graph.facebook.com/', request_token_url=None, access_token_url='/oauth/access_token', authorize_url='https://www.facebook.com/dialog/oauth', consumer_key='<consumer key here>', consumer_secret='<consumer secret here>', request_token_params={'scope': 'email'} )
Step 3 Setup
app = Flask(__name__) app.config.update( SQLALCHEMY_DATABASE_URI='sqlite:///pastebin.db', SECRET_KEY='development-key' ) db = SQLAlchemy(app) oauth = OAuth() facebook = oauth.remote_app('facebook', base_url='https://graph.facebook.com/', request_token_url=None, access_token_url='/oauth/access_token', authorize_url='https://www.facebook.com/dialog/oauth', consumer_key='<consumer key here>', consumer_secret='<consumer secret here>', request_token_params={'scope': 'email'} )
Step 5 Authentication
@app.before_request def check_user_status(): g.user = None if 'user_id' in session: g.user = User.query.get(session['user_id']) @facebook.tokengetter def get_facebook_oauth_token(): return session.get('fb_access_token')
Step 5 Authentication
@app.before_request def check_user_status(): g.user = None if 'user_id' in session: g.user = User.query.get(session['user_id']) @facebook.tokengetter def get_facebook_oauth_token(): return session.get('fb_access_token')
Step 5 Authentication
@app.before_request def check_user_status(): g.user = None if 'user_id' in session: g.user = User.query.get(session['user_id']) @facebook.tokengetter def get_facebook_oauth_token(): return session.get('fb_access_token')
Step 5 Authentication
@app.route('/login') def login(): return facebook.authorize(callback=url_for('facebook_authorized', next=request.args.get('next') or request.referrer or None, _external=True)) @app.route('/logout') def logout(): session.clear() return redirect(url_for('new_paste'))
Step 5 Authentication
@app.route('/login') def login(): return facebook.authorize(callback=url_for('facebook_authorized', next=request.args.get('next') or request.referrer or None, _external=True)) @app.route('/logout') def logout(): session.clear() return redirect(url_for('new_paste'))
Step 5 Authentication
@app.route('/login') def login(): return facebook.authorize(callback=url_for('facebook_authorized', next=request.args.get('next') or request.referrer or None, _external=True)) @app.route('/logout') def logout(): session.clear() return redirect(url_for('new_paste'))
Step 5 Authentication
@app.route('/login') def login(): return facebook.authorize(callback=url_for('facebook_authorized', next=request.args.get('next') or request.referrer or None, _external=True)) @app.route('/logout') def logout(): session.clear() return redirect(url_for('new_paste'))
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
Step 5 Authentication
@app.route('/login/authorized') @facebook.authorized_handler def facebook_authorized(resp): next_url = request.args.get('next') or url_for('new_paste') if resp is None: return redirect(next_url) session['fb_access_token'] = (resp['access_token'], '') me = facebook.get('/me') user = User.query.filter_by(fb_id=me.data['id']).first() if user is None: user = User() user.fb_id = me.data['id'] db.session.add(user) user.display_name = me.data['name'] db.session.commit() session['user_id'] = user.id return redirect(next_url)
@app.route('/my-pastes') def my_pastes(): if g.user is None: return redirect(url_for('login', next=request.url)) pastes = Paste.query.filter_by(user=g.user).all() return render_template('my_pastes.html', pastes=pastes)
@app.route('/my-pastes') def my_pastes(): if g.user is None: return redirect(url_for('login', next=request.url)) pastes = Paste.query.filter_by(user=g.user).all() return render_template('my_pastes.html', pastes=pastes)
@app.route('/my-pastes') def my_pastes(): if g.user is None: return redirect(url_for('login', next=request.url)) pastes = Paste.query.filter_by(user=g.user).all() return render_template('my_pastes.html', pastes=pastes)
@app.route('/my-pastes') def my_pastes(): if g.user is None: return redirect(url_for('login', next=request.url)) pastes = Paste.query.filter_by(user=g.user).all() return render_template('my_pastes.html', pastes=pastes)
Step 7 Templates
<!doctype html> <title>{% block title %}{% endblock %} | Flask Pastebin</title> <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}"> <div class=page> <h1>Flask Pastebin</h1> <ul class=nav> <li><a href="{{ url_for('new_paste') }}">New Paste</a> {% if g.user %} <li><a href="{{ url_for('my_pastes') }}">My Pastes</a> <li><a href="{{ url_for('logout') }}">Sign out ({{ g.user.display_name }})</a> {% else %} <li><a href="{{ url_for('login') }}">Sign in with Facebook</a> {% endif %} </ul> {% block body %}{% endblock %} </div> layout.html
Step 7 Templates
<!doctype html> <title>{% block title %}{% endblock %} | Flask Pastebin</title> <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}"> <div class=page> <h1>Flask Pastebin</h1> <ul class=nav> <li><a href="{{ url_for('new_paste') }}">New Paste</a> {% if g.user %} <li><a href="{{ url_for('my_pastes') }}">My Pastes</a> <li><a href="{{ url_for('logout') }}">Sign out ({{ g.user.display_name }})</a> {% else %} <li><a href="{{ url_for('login') }}">Sign in with Facebook</a> {% endif %} </ul> {% block body %}{% endblock %} </div> layout.html
Step 7 Templates
<!doctype html> <title>{% block title %}{% endblock %} | Flask Pastebin</title> <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}"> <div class=page> <h1>Flask Pastebin</h1> <ul class=nav> <li><a href="{{ url_for('new_paste') }}">New Paste</a> {% if g.user %} <li><a href="{{ url_for('my_pastes') }}">My Pastes</a> <li><a href="{{ url_for('logout') }}">Sign out ({{ g.user.display_name }})</a> {% else %} <li><a href="{{ url_for('login') }}">Sign in with Facebook</a> {% endif %} </ul> {% block body %}{% endblock %} </div> layout.html
Step 7 Templates
<!doctype html> <title>{% block title %}{% endblock %} | Flask Pastebin</title> <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}"> <div class=page> <h1>Flask Pastebin</h1> <ul class=nav> <li><a href="{{ url_for('new_paste') }}">New Paste</a> {% if g.user %} <li><a href="{{ url_for('my_pastes') }}">My Pastes</a> <li><a href="{{ url_for('logout') }}">Sign out ({{ g.user.display_name }})</a> {% else %} <li><a href="{{ url_for('login') }}">Sign in with Facebook</a> {% endif %} </ul> {% block body %}{% endblock %} </div> layout.html
Step 7 Templates
{% extends "layout.html" %} {% block title %}New Paste{% endblock %} {% block body %} <h2>New Paste</h2> <form action="" method=post> <div class=code><textarea name=code cols=60 rows=18></textarea></div> <p><input type=submit value="New Paste"> </form> {% endblock %}
new_paste.html
Step 7 Templates
{% extends "layout.html" %} {% block title %}New Paste{% endblock %} {% block body %} <h2>New Paste</h2> <form action="" method=post> <div class=code><textarea name=code cols=60 rows=18></textarea></div> <p><input type=submit value="New Paste"> </form> {% endblock %}
new_paste.html
Step 7 Templates
{% extends "layout.html" %} {% block title %}New Paste{% endblock %} {% block body %} <h2>New Paste</h2> <form action="" method=post> <div class=code><textarea name=code cols=60 rows=18></textarea></div> <p><input type=submit value="New Paste"> </form> {% endblock %}
new_paste.html
Step 7 Templates
{% extends "layout.html" %} {% block title %}Delete Paste #{{ paste.id }}{% endblock %} {% block body %} <h2>Delete Paste #{{ paste.id }}</h2> <form action="" method=post> <p>Are you sure you want to delete the paste? You cannot undo this. <p> <input type=submit name=yes value=Yes> <input type=submit name=no value=No> </form> {% endblock %}
delete_paste.html
Step 7 Templates
{% extends "layout.html" %} {% block title %}My Pastes{% endblock %} {% block body %} <h2>My Pastes</h2> <ul> {% for paste in pastes %} <li><a href="{{ url_for('show_paste', paste_id=paste.id) }}">#{{ paste.id }}</a> from {{ paste.pub_date.strftime('%Y-%m-%d @ %H:%M') }} {% endfor %} </ul> {% endblock %}
my_pastes.html
Step 8 CSS
body { margin: 0; padding: 0; } body, input { font-size: 16px; font-family: 'Helvetica Neue', sans-serif; } .page { margin: 50px auto; width: 740px; } h1 { margin: 0; font-weight: normal; color: #c00; } a { color: black; } a:hover { color: #c00; } .nav { margin: 0 0 20px 0; list-style: none; padding: 0; } .nav li { display: inline; } .nav li + li:before { content: " // "; } h2 { font-weight: normal; margin: 0; } dl { overflow: auto; font-size: 14px; } dl dt { font-weight: bold; width: 90px; float: left; clear: left; } dl dd { float: left; margin: 0; padding: 0; } pre, textarea { font-family: 'Consolas', monospace; font-size: 14px; background: #eee; padding: 0; margin: 0; } textarea { border: none; width: 720px; } .code, .flash { background: #eee; margin: 10px -30px; padding: 10px 30px; }
Step 9 Flashing
Step 9 Flashing
from flask import flash @app.route('/logout') def logout(): session.clear() flash('You were logged out') return redirect(url_for('new_paste'))
Demo
Debugging
Interactive Shell
?
These slides: http://lucumr.pocoo.org/talks/