Developing Large Web Applications Using a
Micro FrameworkOsvaldo Matos-Junior
once upon a time...
The story starts with an April's Fool's Joke...
How an April Fool's Joke became a Framework with Good Intentions
(PyCon 2011)
The “micro” in microframework means Flask aims to keep the core simple but extensible. Flask won’t make
many decisions for you.(Armin Ronacher)
Why micro?
What's in the Box?● built in development server and debugger● integrated routing system● client side sessions (secure cookies)● django-inspired templating language
Some Numbers● 800 LOC Code● 1500 LOC Tests● 200 A4 Pages of Documentation● over 3900 followers and 550 forks on github
a minimal application in Flask
Flask is Funfrom flask import Flaskapp = Flask(__name__)
@app.route('/')def index(): return 'Hello World!'
if __name__ == '__main__': app.run(debug=True)
Easy to Setup$ pip install Flask$ python hello.py * Running on http://localhost:5000/
What it looks like
debug mode
URL building
from flask import Flask, url_forapp = Flask(__name__)
@app.route('/login')def login(): pass
@app.route('/user/<username>')def profile(username): pass
with app.test_request_context(): print url_for('login') print url_for('login', next='/') print url_for('profile', username='John Doe') print url_for('static', filename='css/style.css', _external=True)
/login/login?next=//user/John%20Doehttp://localhost/static/css/style.css
rendering templates
hello.py
from flask import Flask, render_templateapp = Flask(__name__)
@app.route('/', defaults={'name': 'Flask'})@app.route('/<name>')def index(name): return render_template('hello.html', name=name)
if __name__ == '__main__': app.run(debug=True)
templates/hello.html
<head> <title>Greetings</title></head><body> Hello {{ name }}!</body>
Jinja2 (Django like)<html><head><title>{{ title }}</title></head><body> <ul id="navigation"> {% for item in navigation %} <li><a href="{{ item.href }}" class="{{ 'first' if loop.first }} ">{{ item.caption }}</a></li> {% endfor %} </ul> <h1>{{ title|capitalize|truncate(120) }}</h1> {{ text }}{% include "footer.html" %}</body></html>
Template Filters<h1> {{ title|capitalize|truncate(120) }}</h1>
Built in: capitalize, lower, length, trim, striptags, truncate, urlize ...
Customize: slugify, timesince ...
Macrosheader
footer
content
ads 1
ads 2
related content
300x250
Results for: "query"
GOFLASK
Ttile for resultLong text description for the result. Long text description for the result.
Ttile for resultLong text description for the result. Long text description for the result.
Ttile for resultLong text description for the result. Long text description for the result.
Ttile for resultLong text description for the result. Long text description for the result.
Macros{# ads.html #}{% macro google_adsense(id, width=120, height=120) -%}<script>google_ad_client = "pub-XXXX"; google_ad_slot = "{{id}}";google_ad_width = "{{width}}"; google_ad_height = "{{height}}";<script /><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js" ></script>
{%- endmacro %}
{# sidebar.html #}{% from 'ads.html' import ads_google %}<div>{{ google_adsense('arroba', 300, 250) }}</div><div>{{ google_adsense('ads1', 300, 100) }}</div>{% include "related_content.html" %}<div>{{ google_adsense('ads2', 300, 100) }}</div>
Template Inheritance
header
footer
content 2 R
header 2
footer 2
content 3header
footer
content
Base Template<html><head> <link rel="stylesheet" href="style.css" /> <title>{% block title %}{% endblock %} - My Webpage</title></head><body> <div id="content">{% block content %}{% endblock %}</div> <div id="footer"> {% block footer %} © Copyright 2008 by <a href="http://domain.invalid/">you</a>. {% endblock %} </div></body>
Child Template{% extends "base.html" %}{% block title %}Index{% endblock %}
{% block content %} <h1>Index</h1> <p class="important"> Welcome on my awesome homepage. </p>{% endblock %}
render_template('child.html')<html><head> <link rel="stylesheet" href="style.css" /> <title>Index - My Webpage</title></head><body> <div id="content"><h1>Index</h1> <p class="important"> Welcome on my awesome homepage.</p> </div> <div id="footer">© Copyright 2008 by <a href="http://domain.invalid/">you</a>.</div></body>
more...
Request and Sessionsfrom flask import Flask, session, redirect, url_for, escape, requestapp = Flask(__name__)app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
@app.route('/login', methods=['GET', 'POST'])def login(): if request.method == 'POST': session['username'] = request.form['username'] return redirect(url_for('index')) return ''' <form action="" method="post"> <p><input type=text name=username> <p><input type=submit value=Login> </form>'''
Request and [email protected]('/')def index(): if 'username' in session: return 'Logged in as %s' % escape(session['username']) return 'You are not logged in'
@app.route('/logout')def logout(): # remove the username from the session if it's there session.pop('username', None) return redirect(url_for('index'))
Redirects and Errorsfrom flask import abort, redirect, url_for
@app.route('/')def index(): return redirect(url_for('login'))
@app.route('/login')def login(): abort(401)
@app.errorhandler(404)def page_not_found(error): return render_template('page_not_found.html'), 404
Snippetsimport sqlite3from flask import g
def connect_db(): return sqlite3.connect('/path/to/database.db')
@app.before_requestdef before_request(): g.db = connect_db()
@app.teardown_requestdef teardown_request(exception): g.db.close()
many extensions
Flask-BabelFlask-CouchDBFlask-MongoKit
Flask-LoginFlask-Mail
Flask-ScriptFlask-SQLAlchemy
Flask-TestingFlask-WTF
...
Flask-SQLAlchemyfrom flask import Flaskfrom flaskext.sqlalchemy import SQLAlchemy
app = Flask(__name__)db = SQLAlchemy(app)class User(db.Model): name = db.Column(db.String(40), primary_key=True) email = db.Column(db.String(100))
@@app.route('/user/<name>')def show_user(name): user = User.query.filter_by(name=name).first_or_404() return render_template('user.html', user=user)
Flask-Testingfrom flaskext.testing import TestCasefrom hello import app
class AppTest(TestCase): def create_app(self): return app
def test_index(self): response = self.client.get('/')
self.assert200(response) self.assertTemplateUsed('index.html') title = self.get_cotext_variable('title') self.assertEqual('My Page', title)
larger applications
getting started
jusbrasil/web/
templates/static/
js/css/
views/utils/main.pyconfig.py
tests/bootstrap.shmanage.pyrequires.txt
Folders and Packagesjusbrasil/
web/templates/
noticias/index.htmlview.html
jurisprudencia/views/
__init__.pynoticias.pyjurisprudencia.pydiarios.pylegislacao.py...
def create_app(config=None, app_name=None, blueprints=None):
app_name = app_name or __name__ app = flask.Flask(app_name, static_folder=None) configure_app(app, config) configure_blueprints(app, blueprints) configure_error_handlers(app) configure_database(app) configure_context_processors(app) configure_template_filters(app) configure_before_request(app) configure_extensions(app) configure_views(app) configure_admin(app) return app
Create App
Catching HTTP Errorsdef configure_error_handlers(app): @app.errorhandler(401) def unauthorized(error): flask.flash(u'Para acessar você precisa estar logado.') return flask.redirect(url_for('login', next=request.url,_external=True))
@app.errorhandler(404) def page_not_found(error):
return render("errors/page_not_found.html"), 404
@app.errorhandler(500) def server_error_page(error):
return render("errors/server_error.html"), 500
Own Extensionsfrom jusbrasil.search import poolfrom thriftclient import ThriftClient
class SearchClient(ThriftClient):
def __init__(self, app=None): ThriftClient.__init__(self) self.app = None if app is not None: self.init_app(app)
def init_app(self, app): if not app.config['TESTING']: self.pool = pool.ConnectionPool(
server_list=app.config['SEARCH_SERVERS'],timeout=app.config['SEARCH_TIMEOUT'],pool_size=app.config['SEARCH_POOL_SIZE'])
self.app = app
Logged Users
def get_current_user(): return getattr(flask.g, 'user', None)
def configure_before_request(app):
@app.before_request def load_current_user(): flask.g.user = None if 'user' in session: flask.g.user = load_user_session(session['user'])
Shortcutsfrom jusbrasil.web import cache
@cache.memoize()def get_object_or_404(id, document_type):
# no valid id if id < 0: abort(404)
_object = client.getDocument(document_type, id)
# document not found if _object is None: abort(404) return _object
modularize
Blueprintsimport flaskfrom jusbrasil.web.utils.shortcuts import get_object_or_404
app = flask.Blueprint('jurisprudencia', __name__)
@app.route('/<int:id>/<slug>')def view(id, slug):
juris = get_object_or_404(id, 'jurisprudencia') template = 'jurisprudencia/view.html' return render(template, juris=juris)
Templates{% block title %} {{ juris.title }} {% endblock %}
{% block content %}<div class="jurisprudencia"> <h1>{{ juris.titulo }}</h1>
<div class="ementa">{{ juris.ementa }}</div> <a href="{{ juris.inteiroTeor }}">Download Inteiro Teor</a> <div class="acordao"> <h2>Acórdão</h2> {{ juris.acordao }}</div></div>{% endblock %}
finally...
Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions.
scaling
Osvaldo [email protected]
Q&AQ&A
Referenceshttp://denied.immersedcode.org/http://flask.pocoo.org/http://jinja.pocoo.org/http://werkzeug.pocoo.org/http://www.quora.com/Flaskhttps://github.com/mitsuhiko/flaskhttp://www.slideshare.net/mitsuhiko/flaskhttps://github.com/italomaia/flask-empty
Top Related