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
- Load from a
.cfg
file - The configuration files themselves are actual Python files.
- Only values in uppercase are actually stored in the config object later on.
- Load from the current python module
# Only uppercase keys are added to the config
DEBUG = True
SECRET_KEY = 'development key'
app.config.from_object(__name__)
- Load from a file of which name is specified by env
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.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS') # overrides
app.config.from_mapping({'ABC': 'test'})
Flask
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)
- Dumps the arguments. Pack multipe arugments as
args
into JSON array,kwargs
into JSON object. - Create
Response
object withContent-Type
ofapplication/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
redirect
flask.redirect(location, code=302, Response=None)
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
# 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:
- Reversing is often more descriptive
- URL building will handle escaping
- 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:
Topics
Application Context
- Since one of the pillars of Flask’s design is that you can have more than one application in the same Python process.
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
Cookies
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:
Redirects and Errors
- Exceptions generated by flask are subclasses of
werkzeug.exceptions.HTTPException
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
- The request context internally works like a stack
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
- response object :: just return
- string :: create a response object with it
- tuple ::
(response, status, headers)
or(response, headers)
,headers
can be alist
or adict
. - 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 to404
/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'
>>> 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
Templates
Standard Contexts
config
request
session
g
url_for
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 insidescript
tags:
Patterns
Application Factories
- More flexible, more organized, but more complicated
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
- Resource level settings (e.g when passed as a dictionary)
- Keyword argument settings
- App level configuration settings (e.g. CORS*)
- Default settings