Flask
You can initialize a new flask application by using the Flask
function with the name of the app. It is idiomatic to use the __name__
property for app object naming.
from flask import Flask
app = Flask(__name__)
You can run your flask application with the .run
method.
app.run()
You can run the application in debug mode so that it displays errors on the output webpages by setting the debug
flag to True
as an argument to run
app.run(debug=True)
You can specify a port to run on by passing in the port
kwarg.
app.run(port=80)
Routes
You can define an application route by using the app.route
method as a decorator for your controller functions. The argument to the route
method is the url extension that will route to that controller function.
@app.route("/")
def index():
return "Hello, world!"
You can define a function to run before each server request with before_request
.
@app.before_request
def before():
# do some set up etc. here
You can define a function to run after each server request with after_request
. This passes a response
object through to the inner implementation that needs to be handled in the argument definitions for the function. You must return the response
in after_request
to avoid server errors.
@app.after_request
def before(response):
# do some tear down etc. here
return response
You can define a POST route by using the methods
property of routes. You can get standard data (such as a String) from a POST request by using the request
object’s data
field. This needs to be imported from flask
to be usable.
from flask import request
@app.route("/add", methods=["POST"])
def add():
data = request.data
# do something with the data here
You can handle JSON data from a POST request by using the json
property of the request
object. JSON is parsed from the request
object into python code as a dict
. Don’t forget to add Content-Type: application/json
before testing these requests manually.
@app.route("/echo", methods=["POST"])
def echo():
json_data = request.json
# do something with json_data dict here
You can can handle requests to a route with a single name but multiple methods by using the request.method
property with a conditional.
@app.route("/multi", methods=["GET", "POST"])
def multi():
if request.method == "POST":
# do something with POST data
else:
# send response to GET request
Blueprints
You can split your flask application in a modular fashion using flask’s Blueprint
module. This allows you to define routing in separate modules and then register them in your main app file.
# api.py module file
from flask import Blueprint
blueprint = Blueprint('blueprint', __name__)
@blueprint.route('/message')
def show():
return "Hello, world!"
To register a blueprint in your main flask app you must import
the module file that contains the blue print and then use the register_blueprint
method. Once registered if the user navigates to the url extensions defined in the blueprints they will be served via those controllers.
# app.py
from flask import Flask
from api import api
app = Flask(__name__)
app.register_blueprint(api.blueprint)
You can prefix all of the routes a blueprint with a master route by using the url_prefix
property when registering a blueprint. In the example below this now means the message
route define in the api
blueprint will be available at /api/message
to users.
# app.py
app.register_blueprint(api.blueprint, url_prefix="/api")
JSON
You can send JSON responses by using the jsonify
method. This accepts JSON formatted data (or a Python dict
) as its argument between {}
curly braces. Keys and values must be in string format.
jsonify(
{
"codec": "73-ZXX14", # key value pairs
"users": [ # arrays
"Nelson",
"Lauren",
"Vlad"
],
"scheme": { # nested objects
"platform": "spectrum",
"version": "1.1.2"
}
}
)
Templating
You can render and return a page template by importing the render_template
function from flask and returning it in your flask route with the path to the template you want to render as the argument. The render_template
function will look for a directory called templates
in the directory that the app is being run from to find a file path to the file you want to render.
from flask import render_template
# --snip--
@app.get("/")
def index():
return render_template("index.html")
Jinja
Flask uses the jinja2
templating engine.
You can embed jinja
code for templating and logic by using the {[%] [%]}
curly brace, percent syntax indicators.
{[%] body [%]}
<!-- code here -->
{[%] endblock [%]}
You can interpolate code results as a string using `` double curly braces.
<link rel="stylesheet" href="">
Templates
The jinja2
engine works by inheriting from other templates by name and then use named block
s to insert content. For example a very simple template might look like the base.html
file below which defines a block
called body
.
<!-- base.html -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
{[%] block body [%]}{[%] endblock [%]}
</body>
</html>
To inherit from a template use the extends
keyword followed by the name of the template as a string.
<!-- index.html -->
{[%] extends 'base.html' [%]}
You can insert content for a templated block by inserting regular HTML content between the block
and endblock
tags. This will then inject that content into the template when it is returned by flask.
<!-- index.html -->
{[%] block body [%]}
<h1>Hello, world!</h1>
{[%] endblock [%]}
CSS and JS
You can import static content such as CSS and Javascript by setting their href
and src
respectively interpolating a file path using Jinja’s `` interpolation code and Flask’s url_for
method which takes the name of the static
directory as its first argument and then a file path to the static file within that folder. The example below loads main.css
from the static/css/
directory and index.js
from the static/js
folder and inserts the correct file paths thus loading the resources.
<link rel="stylesheet" href="">
<script src=""></script>
SQLAlchemy and Database Sessions
One way to control database sessions for different controller routes is to open and close them in the before_reuqest
and after_request
functions then make the scope session
object available to the route using it via the g
lobal scope of your flask application. In the code below app.py
sets up opening and closing session
s before each request to the server, the individual blueprint routes can then use the session
as required by importing the g
variable from flask. Flask g
isn’t really global in the traditional sense, while it encompasses the application context, each new request wipes the old g
scope and keeps it just for that request.
# app.py
from database import Session # import the main Session object
from flask import Flask, g
# --snip--
@app.before_request
def before():
g.session = Session()
@app.after_request
def after(response):
g.session.close()
# controller.py
# some other controller blueprint with routes
from flask import g
# --snip--
@blueprint.route("/users")
def save_user():
user = User(name="Jimothy", age=10)
g.session.add(user)
g.session.commit()
Testing
You can test your flask application by creating a pytest.fixture
that initialises the app
in "TESTING"
mode (this suppresses exception handling so that the test environment can more easily manage errors with meaningful messages) and then yield
or return
a test_client()
to your test functions. Below is the simplest example of a test set up for a flask application. This would usually be longer with database integration etc.
import pytest
from app import app # import a flask app that has been initialised in your main file
@pytest.fixture
def client():
app.config["TESTING"] = True
with app.test_client() as client:
yield client # send the test client to test methods
You can test a flask route by calling the get
method on a client route. This also works with blueprint define routes, you just need to include the absolute url extension to that route. You can access and test against the status
of a response
object, this comes in the form of a string.
def test_index(client):
response = client.get("/")
assert response.status == '200 OK'
You can access the data
of a response
by using the data
property.
def test_index(client):
response = client.get("/")
assert response.data != None
You can test the string data
of that response
which comes in the form of byte data and so needs to be prepended by the b
character when testing strings to indicate it is a byte string literal.
def test_index(client):
response = client.get("/")
assert response.data == b'This is a message'
You test a POST
route by using post
method on the flask test_client
object and passing data
. The example below shows a route that reverses a string that is sent to it.
def test_post_data(client):
response = client.post("/reverse", data="Mandelbrot")
assert response.data == b'torblednaM'
You can send JSON to post routes by adding a json.dump
ed dict
with content_type
set to application/json
. The /echo
route below accepts JSON and send back as a string whatever value is stored in the foo
key.
import json
def test_post_json(client):
response = client.post("/echo",
json.dumps(dict(foo='bar'),
content_type='application/json')
response.json == b'bar'