$30 off During Our Annual Pro Sale. View Details »

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
  2. Pocoo Friday, 2 March, 12

  3. Friday, 2 March, 12

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

  5. MICROFramework Friday, 2 March, 12

  6. MICRO Friday, 2 March, 12

  7. Database Abstraction Friday, 2 March, 12

  8. Database Abstraction Friday, 2 March, 12

  9. Form Validation Friday, 2 March, 12

  10. Form Validation Friday, 2 March, 12

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

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

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

  14. Templating WSGI & Friday, 2 March, 12

  15. Tools Friday, 2 March, 12

  16. Friday, 2 March, 12

  17. gunicorn Friday, 2 March, 12

  18. gunicorn gevent Friday, 2 March, 12

  19. gunicorn gevent nginx Friday, 2 March, 12

  20. Friday, 2 March, 12

  21. unittest2/nose Friday, 2 March, 12

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

  23. Friday, 2 March, 12

  24. fabric Friday, 2 March, 12

  25. fabric virtualenv Friday, 2 March, 12

  26. fabric virtualenv jenkins Friday, 2 March, 12

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

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

  29. Friday, 2 March, 12

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

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

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

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

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

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

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

    return "Hello World!" if __name__ == "__main__": app.run() Friday, 2 March, 12
  37. $ pythonhello.py Friday, 2 March, 12

  38. Werkzeug Router Friday, 2 March, 12

  39. Friday, 2 March, 12

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

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

  42. @app.route(‘/dashboard’) @app.route(‘/’) @app.route(‘/pages/<path:name>’) Friday, 2 March, 12

  43. @app.route(‘/dashboard’) @app.route(‘/’) @app.route(‘/pages/<path:name>’) @app.route(‘/user/<int:user_id>’) Friday, 2 March, 12

  44. @app.route(‘/dashboard’) @app.route(‘/’) @app.route(‘/pages/<path:name>’) @app.route(‘/user/<int:user_id>’) @app.route(‘/posts/<int:year>/<int:month>’) Friday, 2 March, 12

  45. @app.route(‘/dashboard’) @app.route(‘/’) @app.route(‘/pages/<path:name>’) @app.route(‘/user/<int:user_id>’) @app.route(‘/posts/<int:year>/<int:month>’) @app.route(‘/<string(length=2):lang>’) Friday, 2 March, 12

  46. Custom Converters Friday, 2 March, 12

  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
  48. Testing Friday, 2 March, 12

  49. Friday, 2 March, 12

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

  51. Friday, 2 March, 12

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

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

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

    12
  55. Useful Extensions Friday, 2 March, 12

  56. Friday, 2 March, 12

  57. Flask-Login Friday, 2 March, 12

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

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

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

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

  62. ORM Integration Friday, 2 March, 12

  63. Friday, 2 March, 12

  64. SQLAlchemy Friday, 2 March, 12

  65. SQLAlchemy MongoKit Friday, 2 March, 12

  66. SQLAlchemy MongoKit Pycassa Friday, 2 March, 12

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

  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 '<User %r>' % self.username Friday, 2 March, 12
  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
  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
  71. Callbacks/hooks Friday, 2 March, 12

  72. Friday, 2 March, 12

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

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

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

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

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

  78. Signals via Blinker Friday, 2 March, 12

  79. Friday, 2 March, 12

  80. flask.template_rendered Friday, 2 March, 12

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

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

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

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

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

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

  87. API Design Friday, 2 March, 12

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

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

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

    12
  91. Blueprints Friday, 2 March, 12

  92. from flask import Blueprint, render_template, abort from jinja2 import TemplateNotFound

    static_page = Blueprint('static_page', __name__, template_folder='templates') @static_page.route('/<page>') def show(page): try: return render_template('pages/%s.html' % page) except TemplateNotFound: abort(404) Friday, 2 March, 12
  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
  94. Blueprints have their own templates, static files, and callbacks/hooks. Friday,

    2 March, 12
  95. Pluggable Views Friday, 2 March, 12

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

    2 March, 12
  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
  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
  99. Method-Based Dispatching Friday, 2 March, 12

  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
  101. QUESTIONS? Friday, 2 March, 12

  102. Fictive Kin Friday, 2 March, 12

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