Step 1: Creating a reusable package

First, let’s start by creating a small reusable package that we would possibly like to use in many different applications. The package consists of:

  • a Flask blueprint + templates.
  • a Click command line interface.
  • default configuration for the package.

Here’s how the directory structure looks like:

mymodule/__init__.py  (empty)
mymodule/cli.py
mymodule/config.py
mymodule/views.py
mymodule/templates/mymodule.html
mymodule/templates/mymodule_base.html

Default configuration

The package can provide default configuration values in a config.py that it expects to be set. The values are merged into the Flask applications configuration and can be overwritten by each instance of an application.

1
2
3
# mymodule/config.py

MYMODULE_GREETING = "Hello, World!"

Blueprint

The package can also provide a blueprint. The blueprint will automatically be registered on the Flask application by Flask-AppFactory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# mymodule/views.py

from flask import Blueprint, current_app, render_template

blueprint = Blueprint(
    'mymodule',
    __name__,
    template_folder='templates',
)

@blueprint.route("/")
def index():
    return render_template(
        'mymodule.html',
        greeting=current_app.config['MYMODULE_GREETING'],
    )

This example blueprint simply renders the template mymodule.html and pass it the value of MYMODULE_GREETING (line 15) that we ensured was set in config.py. Notice, also that the Blueprint’s template folder is set in line 8 (without it, the templates in the next section are not found).

Templates

The package provides two templates mymodule.html and mymodule_base.html , where mymodule.html simply extends mymodule_base.html. The reason for this slightly odd method, is that it allows other packages to easily modify the templates without copy/pasting the entire template code. Another package simply creates a mymodule.html also extending from mymodule_base.html, and only overwrites the few template blocks that it needs to customize.

1
2
{# mymodule/templates/mymodule.html #}
{% extends "mymodule_base.html" %}
1
2
{# mymodule/templates/mymodule_base.html #}
{% block body %}{{greeting}}{% endblock %}

Note

It is usually a good idea to put your templates into a subfolder to avoid name conflicts between multiple packages.

Command Line interface

Finally, our package provide some simple CLI commands in cli.py that will be merged into a single CLI application that can used to manage a Flask application.

The CLI is based on the Click Python package which has good extensive documentation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# mymodule/cli.py

import click
from flask import current_app
from flask_cli import with_appcontext

@click.command()
def testsimple():
    """Command without application context."""
    click.echo("Test")

@click.command()
@with_appcontext
def testapp():
    """Command with application context."""
    click.echo(current_app.name)

commands = [testsimple, testapp]

Flask-AppFactory expects to find a variable commands in cli.py with a list of commands to register (line 18). Using the @with_appcontext (line 13) decorator the commands can access the Flask application context (e.g current_app). Without the decorator the application is not fully loaded in order to speed up the CLI.