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.

Bd21ebabfbce06b235bc0516c1eb2912?s=128

Joël Perras

March 02, 2012
Tweet

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