Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Large-Scale Applications with Flask: Doing More With Less

Large-Scale Applications with Flask: Doing More With Less

In this session I show you how you can take Flask, a so-called "microframework", and write readable, usable, testable and intelligent code for all of your macro-scale applications. We'll go through basic API design, ORM integration (including some popular non-relational databases), modular design with blueprints, and testing. By the end of this talk, you'll understand why Flask is the little framework that lets you do a lot, and be armed with the tools & knowledge to write applications of all sizes.

Joël Perras

March 02, 2012
Tweet

More Decks by Joël Perras

Other Decks in Technology

Transcript

  1. DOING MORE WITH LESS
    Large Scale Apps with
    FLASK
    Friday, 2 March, 12

    View Slide

  2. Pocoo
    Friday, 2 March, 12

    View Slide

  3. Friday, 2 March, 12

    View Slide

  4. JINJA
    FLASK
    PYGMENTS
    WERKZEUGSPHINX
    ...
    Friday, 2 March, 12

    View Slide

  5. MICROFramework
    Friday, 2 March, 12

    View Slide

  6. MICRO
    Friday, 2 March, 12

    View Slide

  7. Database Abstraction
    Friday, 2 March, 12

    View Slide

  8. Database Abstraction
    Friday, 2 March, 12

    View Slide

  9. Form Validation
    Friday, 2 March, 12

    View Slide

  10. Form Validation
    Friday, 2 March, 12

    View Slide

  11. Django-ish Admin
    Friday, 2 March, 12

    View Slide

  12. Django-ish Admin
    Friday, 2 March, 12

    View Slide

  13. Jinja 2 Werkzeug
    &
    Friday, 2 March, 12

    View Slide

  14. Templating WSGI
    &
    Friday, 2 March, 12

    View Slide

  15. Tools
    Friday, 2 March, 12

    View Slide

  16. Friday, 2 March, 12

    View Slide

  17. gunicorn
    Friday, 2 March, 12

    View Slide

  18. gunicorn
    gevent
    Friday, 2 March, 12

    View Slide

  19. gunicorn
    gevent
    nginx
    Friday, 2 March, 12

    View Slide

  20. Friday, 2 March, 12

    View Slide

  21. unittest2/nose
    Friday, 2 March, 12

    View Slide

  22. unittest2/nose
    lettuce
    Friday, 2 March, 12

    View Slide

  23. Friday, 2 March, 12

    View Slide

  24. fabric
    Friday, 2 March, 12

    View Slide

  25. fabric
    virtualenv
    Friday, 2 March, 12

    View Slide

  26. fabric
    virtualenv
    jenkins
    Friday, 2 March, 12

    View Slide

  27. RESTful/ish APIs
    Friday, 2 March, 12

    View Slide

  28. Warning
    CODE BEYOND THIS POINT
    Friday, 2 March, 12

    View Slide

  29. Friday, 2 March, 12

    View Slide

  30. from flask import Flask
    Friday, 2 March, 12

    View Slide

  31. from flask import Flask
    app = Flask(__name__)
    Friday, 2 March, 12

    View Slide

  32. from flask import Flask
    app = Flask(__name__)
    @app.route("/")
    Friday, 2 March, 12

    View Slide

  33. from flask import Flask
    app = Flask(__name__)
    @app.route("/")
    def hello():
    Friday, 2 March, 12

    View Slide

  34. from flask import Flask
    app = Flask(__name__)
    @app.route("/")
    def hello():
    return "Hello World!"
    Friday, 2 March, 12

    View Slide

  35. from flask import Flask
    app = Flask(__name__)
    @app.route("/")
    def hello():
    return "Hello World!"
    if __name__ == "__main__":
    Friday, 2 March, 12

    View Slide

  36. from flask import Flask
    app = Flask(__name__)
    @app.route("/")
    def hello():
    return "Hello World!"
    if __name__ == "__main__":
    app.run()
    Friday, 2 March, 12

    View Slide

  37. $ pythonhello.py
    Friday, 2 March, 12

    View Slide

  38. Werkzeug Router
    Friday, 2 March, 12

    View Slide

  39. Friday, 2 March, 12

    View Slide

  40. @app.route(‘/’)
    Friday, 2 March, 12

    View Slide

  41. @app.route(‘/dashboard’)
    @app.route(‘/’)
    Friday, 2 March, 12

    View Slide

  42. @app.route(‘/dashboard’)
    @app.route(‘/’)
    @app.route(‘/pages/’)
    Friday, 2 March, 12

    View Slide

  43. @app.route(‘/dashboard’)
    @app.route(‘/’)
    @app.route(‘/pages/’)
    @app.route(‘/user/’)
    Friday, 2 March, 12

    View Slide

  44. @app.route(‘/dashboard’)
    @app.route(‘/’)
    @app.route(‘/pages/’)
    @app.route(‘/user/’)
    @app.route(‘/posts//’)
    Friday, 2 March, 12

    View Slide

  45. @app.route(‘/dashboard’)
    @app.route(‘/’)
    @app.route(‘/pages/’)
    @app.route(‘/user/’)
    @app.route(‘/posts//’)
    @app.route(‘/’)
    Friday, 2 March, 12

    View Slide

  46. Custom Converters
    Friday, 2 March, 12

    View Slide

  47. from werkzeug.routing import BaseConverter
    class ListConverter(BaseConverter):
    def to_python(self, value):
    return value.split(',')
    def to_url(self, values):
    return
    ','.join(BaseConverter.to_url(value)
    for value in values)
    app = Flask(__name__)
    app.url_map.converters['list'] = ListConverter
    Friday, 2 March, 12

    View Slide

  48. Testing
    Friday, 2 March, 12

    View Slide

  49. Friday, 2 March, 12

    View Slide

  50. UNITTEST
    FACTORY_BOY
    LETTUCE
    NOSEMOCK
    ...
    Friday, 2 March, 12

    View Slide

  51. Friday, 2 March, 12

    View Slide

  52. Thread/Context Locals
    Friday, 2 March, 12

    View Slide

  53. with app.test_request_context('/posts?sort=asc&limit=10'):
    Friday, 2 March, 12

    View Slide

  54. with app.test_client() as client:
    result = client.get('/posts?sort=asc&limit=10')
    Friday, 2 March, 12

    View Slide

  55. Useful Extensions
    Friday, 2 March, 12

    View Slide

  56. Friday, 2 March, 12

    View Slide

  57. Flask-Login
    Friday, 2 March, 12

    View Slide

  58. Flask-Login
    Flask-Testing
    Friday, 2 March, 12

    View Slide

  59. Flask-Login
    Flask-Testing
    Flask-WTForms
    Friday, 2 March, 12

    View Slide

  60. Flask-Login
    Flask-Testing
    Flask-WTForms
    Flask-Bcrypt
    Friday, 2 March, 12

    View Slide

  61. Flask-Login
    Flask-Testing
    Flask-WTForms
    Flask-Bcrypt
    Flask-Assets
    Friday, 2 March, 12

    View Slide

  62. ORM Integration
    Friday, 2 March, 12

    View Slide

  63. Friday, 2 March, 12

    View Slide

  64. SQLAlchemy
    Friday, 2 March, 12

    View Slide

  65. SQLAlchemy
    MongoKit
    Friday, 2 March, 12

    View Slide

  66. SQLAlchemy
    MongoKit
    Pycassa
    Friday, 2 March, 12

    View Slide

  67. SQLAlchemy
    MongoKit
    Pycassa
    CouchDB
    Friday, 2 March, 12

    View Slide

  68. from flask import Flask
    from flaskext.sqlalchemy import SQLAlchemy
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
    db = SQLAlchemy(app)
    class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)
    def __init__(self, username, email):
    self.username = username
    self.email = email
    def __repr__(self):
    return '' % self.username
    Friday, 2 March, 12

    View Slide

  69. from flask import Flask
    from mongokit import Connection, Document
    # configuration
    MONGODB_HOST = 'localhost'
    MONGODB_PORT = 27017
    # create the little application object
    app = Flask(__name__)
    app.config.from_object(__name__)
    # connect to the database
    connection = Connection(app.config['MONGODB_HOST'],
    app.config['MONGODB_PORT'])
    Friday, 2 March, 12

    View Slide

  70. class Post(Document):
    structure = {
    'title':unicode,
    'body':unicode,
    'author':unicode,
    'date_creation':datetime.datetime,
    'rank':int,
    'tags': [unicode],
    }
    required_fields = ['title','author', 'date_creation']
    default_values = {'rank':0, 'date_creation': datetime.datetime.utcnow}
    Friday, 2 March, 12

    View Slide

  71. Callbacks/hooks
    Friday, 2 March, 12

    View Slide

  72. Friday, 2 March, 12

    View Slide

  73. @app.before_request
    Friday, 2 March, 12

    View Slide

  74. @app.before_request
    @app.after_request
    Friday, 2 March, 12

    View Slide

  75. @app.before_request
    @app.after_request
    @app.before_first_request
    Friday, 2 March, 12

    View Slide

  76. @app.before_request
    @app.after_request
    @app.before_first_request
    @app.errorhandler
    Friday, 2 March, 12

    View Slide

  77. @app.before_request
    @app.after_request
    @app.before_first_request
    @app.errorhandler
    ...
    Friday, 2 March, 12

    View Slide

  78. Signals via Blinker
    Friday, 2 March, 12

    View Slide

  79. Friday, 2 March, 12

    View Slide

  80. flask.template_rendered
    Friday, 2 March, 12

    View Slide

  81. flask.request_started
    flask.template_rendered
    Friday, 2 March, 12

    View Slide

  82. flask.request_started
    flask.request_finished
    flask.template_rendered
    Friday, 2 March, 12

    View Slide

  83. flask.request_started
    flask.request_finished
    flask.template_rendered
    flask.got_request_exception
    Friday, 2 March, 12

    View Slide

  84. flask.request_started
    flask.request_finished
    flask.template_rendered
    flask.got_request_exception
    flask.request_tearing_down
    Friday, 2 March, 12

    View Slide

  85. In-process event
    dispatching
    Friday, 2 March, 12

    View Slide

  86. Not the same as
    callbacks/hooks
    Friday, 2 March, 12

    View Slide

  87. API Design
    Friday, 2 March, 12

    View Slide

  88. Start thinking in terms of
    datastructures
    Friday, 2 March, 12

    View Slide

  89. And breaking up your
    application in to services
    Friday, 2 March, 12

    View Slide

  90. Instead of staying in the
    MVC Bubble.
    Friday, 2 March, 12

    View Slide

  91. Blueprints
    Friday, 2 March, 12

    View Slide

  92. from flask import Blueprint, render_template, abort
    from jinja2 import TemplateNotFound
    static_page = Blueprint('static_page', __name__,
    template_folder='templates')
    @static_page.route('/')
    def show(page):
    try:
    return render_template('pages/%s.html' % page)
    except TemplateNotFound:
    abort(404)
    Friday, 2 March, 12

    View Slide

  93. from flask import Flask
    from myapp.static_page import static_page
    app = Flask(__name__)
    app.register_blueprint(static_page, url_prefix= ‘/pages’)
    Friday, 2 March, 12

    View Slide

  94. Blueprints have their own
    templates, static files,
    and callbacks/hooks.
    Friday, 2 March, 12

    View Slide

  95. Pluggable Views
    Friday, 2 March, 12

    View Slide

  96. @app.route('/users/')
    def show_users(page):
    users = User.query.all()
    return render_template('users.html', users=users)
    Friday, 2 March, 12

    View Slide

  97. from flask.views import View
    class ShowUsers(View):
    def dispatch_request(self):
    users = User.query.all()
    return render_template('users.html', objects=users)
    app.add_url_rule('/users/', ShowUsers.as_view('show_users'))
    Friday, 2 March, 12

    View Slide

  98. from flask.views import View
    class ListView(View):
    def get_template_name(self):
    raise NotImplementedError()
    def render_template(self, context):
    return render_template(self.get_template_name(), **context)
    def dispatch_request(self):
    context = {'objects': self.get_objects()}
    return self.render_template(context)
    class UserView(ListView):
    def get_template_name(self):
    return 'users.html'
    def get_objects(self):
    return User.query.all()
    Friday, 2 March, 12

    View Slide

  99. Method-Based
    Dispatching
    Friday, 2 March, 12

    View Slide

  100. from flask.views import MethodView
    class User(MethodView):
    def get(self):
    users = User.query.all()
    ...
    def post(self):
    user = User.from_form_data(request.form)
    ...
    app.add_url_rule('/users/', view_func=User.as_view('users'))
    Friday, 2 March, 12

    View Slide

  101. QUESTIONS?
    Friday, 2 March, 12

    View Slide

  102. Fictive Kin
    Friday, 2 March, 12

    View Slide

  103. @jperras
    Joël Perras
    http://nerderati.com
    Friday, 2 March, 12

    View Slide