Flask

Table of Contents

Overview

/<project-root>
  /<package>
    __init__.py
    /static
    /templates
  setup.py
  MANIFEST.in

setup.py:

from setuptools import setup

setup(
    name='flaskr',
    packages=['flaskr'],
    include_package_data=True,
    install_requires=[
        'flask',
    ],
    setup_requires=[
        'pytest-runner',
    ],
    tests_require=[
        'pytest',
    ],
)

Reference

Config

app.config.from_pyfile('yourconfig.cfg')
# Only uppercase keys are added to the config
DEBUG = True
SECRET_KEY = 'development key'
app.config.from_object(__name__)
export YOURAPPLICATION_SETTINGS='/path/to/config/file'
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

Certain configuration values are also forwarded to the Flask object so you can read and write them from there:

app = Flask(__name__)
app.config['DEBUG'] = True

# equivalent to above
app.debug = True
app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS') # overrides
app.config.from_mapping({'ABC': 'test'})

Flask

app = Flask('yourapplication')
app = Flask(__name__.split('.')[0])

If you are using a single module, name is always the correct value. If you however are using a package, it’s usually recommended to hardcode the name of your package there.

g

Stored on the application context and no longer on the request context which means it becomes available if only the application context is bound and not yet a request.

jsonify

flask.json.jsonify(*args, **kwargs)
  1. Dumps the arguments. Pack multipe arugments as args into JSON array, kwargs into JSON object.
  2. Create Response object with Content-Type of application/json

open_resource

/myapplication.py
/schema.sql
/static
    /style.css
/templates
    /layout.html
    /index.html

The name of the package is used to resolve resources from inside the package or the folder the module is contained in

with app.open_resource('schema.sql') as f:
    contents = f.read()
    do_something_with(contents)

redirect

flask.redirect(location, code=302, Response=None)
@app.route('/')
def index():
    return redirect(url_for('login'))

render_template

flask.render_template(template_name_or_list, **context)
context
the variables that should be available in the context of the template.

request

# A MultiDict with the parsed contents of the query string.(The part in the URL after the question mark).
request.args.get('value', type=int)

Use request.get_json(), which is later added for consistency, instead of request.json

# force  if set to True the mimetype is ignored.
# silent if set to True this method will fail silently and return None.
# cache  if set to True the parsed JSON data is remembered on the request.
request.get_json(force=False, silent=False, cache=True)

MultiDict

>>> d = TypeConversionDict(foo='42', bar='blub')
>>> d.get('foo', type=int)
42
>>> d.get('bar', -1, type=int)
-1

route

@app.route('/users/', defaults={'page': 1})
@app.route('/users/page/<int:page>')
def show_users(page):
    pass
rule the URL rule as string
endpoint the endpoint for the registered URL rule. Flask itself assumes that the name of the view function is the name of the endpoint if not explicitly stated.
viewfunc the function to call when serving a request to the provided endpoint. If this is not provided one can specify the function later by storing it in the viewfunctions dictionary with the endpoint as key.
defaults A dictionary with defaults for this rule. See the example above for how defaults work.
subdomain specifies the rule for the subdomain in case subdomain matching is in use. If not specified the default subdomain is assumed.
**options the options to be forwarded to the underlying Rule object. A change to Werkzeug is handling of method options. methods is a list of methods this rule should be limited to (GET, POST etc.). By default a rule just listens for GET (and implicitly HEAD). Starting with Flask 0.6, OPTIONS is implicitly added and handled by the standard request handling. They have to be specified as keyword arguments.

url_for

flask.url_for(endpoint, **values)
url_for('static', filename='style.css')
# relative to current Blueprint
url_for('.index')

# Generate absolute URL
url_for('.index', _external=True)

Generates a URL to the given endpoint with the method provided. This is better than hard-coded URLs as following reasons:

  1. Reversing is often more descriptive
  2. URL building will handle escaping
  3. If your application is placed outside the URL root

test_client

# propgate excetions to test_client
app.testing = True
client = app.test_client()

# keep client open until the end of with block to test with contexts
# You can now read the session or other context variables
with app.test_client() as c:
    pass

# If you want to modify the current session
# Use session_transaction() as following:
with client.session_transaction() as sess:
    sess.update(d)

testclient DOES NOT support dict-json. You have to manually serialize dict to json and specify content_type as follows:

client.post(url,
            content_type='application/json',
            data=json.dumps(d))

Topics

Application Context

from flask import Flask, current_app

app = Flask(__name__)
with app.app_context():
    # within this block, current_app points to app.
    print current_app.name
import sqlite3
from flask import g

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = connect_to_database()
    return db

@app.teardown_appcontext
def teardown_db(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

from werkzeug.local import LocalProxy
db = LocalProxy(get_db)

Blueprints

flask.Blueprint(name, import_name, ...)
name
Use as the prefix of the blueprint routes
import_name
Same as Flask, used for resolve the relative path for resources.
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound

simple_page = Blueprint('simple_page', __name__,
                        template_folder='templates')

@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
    try:
        return render_template('pages/%s.html' % page)
    except TemplateNotFound:
        abort(404)
from flask import Flask
from yourapplication.simple_page import simple_page

app = Flask(__name__)
app.register_blueprint(simple_page)
app.register_blueprint(simple_page, url_prefix='/pages')

Access config within Blueprints

Use flask.current_app, but be careful that current_app is only accessible under the request context.:

from flask import current_app as app
@api.route('/info/', methods = ['GET'])
def get_account_num():
    num = app.config["INFO"]

Commands

@app.cli.command('initdb')
def initdb_command():
    pass
$ flask initdb

Cookies

request.cookies.get('username')
resp = make_response(render_template(...))
resp.set_cookie('username', 'the username')

HTTP Methods

OPTIONS
Starting with Flask 0.6, this is implemented for you automatically.

Message Flashing

flash('You were successfully logged in')
return redirect(url_for('index'))

@app.route('/')
def index():
    return render_template('index.html')

The template cotains following code:

{% with messages = get_flashed_messages() %}

Redirects and Errors

from flask import abort, redirect, render_template, url_for

@app.route('/')
def index():
    return redirect(url_for('login'))

@app.route('/login')
def login():
    abort(401)
    this_is_never_executed()

@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

Request Context

def wsgi_app(self, environ):
    with self.request_context(environ):
        try:
            response = self.full_dispatch_request()
        except Exception as e:
            response = self.make_response(self.handle_exception(e))
        return response(environ, start_response)

Responses

  1. response object :: just return
  2. string :: create a response object with it
  3. tuple :: (response, status, headers) or (response, headers), headers can be a list or a dict.
  4. WSGI application :: covert it to a response object.

Routing

@app.route('/')
def index():
    pass

@app.route('/hello')
def hello():
    pass

@app.route('/user/<username>')
def show_user_profile(username):
    pass

@app.route('/post/<int:post_id>')
def show_post(post_id):
    pass
@bp.route('/<user>/', defaults={'name': None})
@bp.route('/<user>/<path:name>')
def query(user, name):
    pass

Trailing slashs:

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'
routes defined with trailing slash
/projects is redirected to /projects/
routes defined without trailing slash
/about/ goes to 404
/test/<path:code>
`code` can include /

Sessions

The way Flask does this is by using a signed cookie.

from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)

@app.route('/')
def index():
    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])
    return 'You are not logged in'

# set the secret key.  keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
@app.before_request
def make_session_permanent():
    session.permanent = True
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'

Just take that thing and copy/paste it into your code and you're done.

Signals

from flask import template_rendered
from contextlib import contextmanager

@contextmanager
def captured_templates(app):
    recorded = []
    def record(sender, template, context, **extra):
        recorded.append((template, context))
    template_rendered.connect(record, app)
    try:
        yield recorded
    finally:
        template_rendered.disconnect(record, app)
with captured_templates(app) as templates:
    rv = app.test_client().get('/')
    assert rv.status_code == 200
    assert len(templates) == 1
    template, context = templates[0]
    assert template.name == 'index.html'
    assert len(context['items']) == 10
from flask import template_rendered

@template_rendered.connect_via(app)
def when_template_rendered(sender, template, context, **extra):
    print 'Template %s is rendered with %s' % (template.name, context)

Static Files

url_for('static', filename='style.css')

Templates

Standard Contexts

tojson

tojson(): This function converts the given object into JSON representation.

Note that inside script tags no escaping must take place, so make sure to disable escaping with |safe before Flask 0.10 if you intend to use it inside script tags:

<script type=text/javascript>
    doSomethingWith({{ user.username|tojson|safe }});
</script>

Patterns

Application Factories

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    from yourapplication.model import db
    db.init_app(app)

    from yourapplication.views.admin import admin
    from yourapplication.views.frontend import frontend
    app.register_blueprint(admin)
    app.register_blueprint(frontend)

    return app

Extensions

flask-cors

The settings for CORS are determined in the following order

  1. Resource level settings (e.g when passed as a dictionary)
  2. Keyword argument settings
  3. App level configuration settings (e.g. CORS*)
  4. Default settings
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "*"}})

@app.route("/api/v1/users")
def list_users():
  return "user example"