Developing Large Web Applications Using a Micro Framework

Post on 08-Nov-2014

58 views 3 download

Tags:

description

Flask is a micro-framework written in python for web application development. Is "micro" because it keeps your core simple. However, is very extensible and delegates the responsibility for the developer to choose the preferred technologies, e.g. database or template rendering system. Understand how Flask can be used to develop a simple application or large web portals

Transcript of Developing Large Web Applications Using a Micro Framework

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 %} &copy; 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">&copy; 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 Sessions@app.route('/')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 Matos-Juniortupy@jusbrasil.com.br

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