Flask web dev: Always use application factories

Flask web development tip number 1

18 Jun '16

Hey there! Over two years later, I’ve made a (hopefully improved) post about application factories and blueprints.

Flask is a web microframework for Python. It’s small, but because it’s so easy to understand it’s also extremely extensible. No more bloat.

I’m hoping to share some tips from developing and deploying several large Flask applications, some which aren’t obvious from the documentation.

Tip 1: Always use an application factory

The documentation does go over application factories, but completely glosses over most benefits.

App factories have a pretentious name, but basically they wrap the initialisation of the application in a method. Sounds like the obvious way to do it, but many Flask examples put the init code inside the module so that when you import the module the application is initialised. This sounds easier, but actually makes it harder in the long run, when you want to control initialisation.

TL;DR: Application factories get you:

  1. Easier deployment
  2. Clearer dependencies
  3. Testing

Example 1: Deployment

Your production application will have a different configuration than the debug one. One (terrible) solution is “intelligent” configuration files that use environmental variables or hostnames, and it usually goes wrong. With an app factory, you can easily tell it which config to use:

from example import app
# app is already initialised
# can't change the config or database connection

from example import create_app
# app isn't initialised, we just imported the factory
app = create_app(DB_CONN="production") # now it's initialised

Remember that the factory can provide default configuration values. So the development server script looks roughly like this:

from example import create_app
if __name__ == '__main__':
    app = create_app()
    app.run()  # using the default, debug database connection

But the WSGI script looks like this:

from example import create_app
application = create_app(DB_CONN="production")

Much less chance of nuking the production database.

Example 2: Dependencies

By not having an initialised application to import, you have to be much more clear about dependencies. This is a good thing, especially if you want your application to grow. Personally, I find it demystifies relationships and avoids circular import hell. People are put off by late initialisation, but it’s really easy. For example, when you use SQLAlchemy, you need a database object:

# __init__.py
app = Flask(__name__)
db = SQLAlchemy(app)

# models.py
from example import db

class User(db.Model):

When you use an app factory, this won’t work any more. But it does give you the opportunity to express the relationships more clearly:

# __init__.py
def create_app():
    app = Flask(__name__)
    from example.models import db
    return app

# models.py
db = SQLAlchemy()

class User(db.Model):

Now the database object lives with the other database functionality, and is only initialised later. It doesn’t seem like much, but suddenly writing blueprints is also easier: If you need anything database related, you only need to import from models.py.

Blueprints allow for modular applications, are a great idea, and pretty much the only way to keep the codebase of medium or large applications sane. Using an app factory forces you to use blueprints, this is a good thing (see Google for now, maybe I’ll write about this later).

Example 3: Testing

Really, this is just example 1 again.

Good luck with Flask!

Python, Flask, SQLAlchemy

Newer Older