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.