Using an Application Factory
`FLASK_ENV="development" FLASK_APP="stock_app:create_app" flask run`
Application Factories & Configuration
Flask gives us a powerful tool to be able to simply start building a web server with essentially three lines of code. This is great to start but as our application becomes more complicated, this simplicity can come back to bite us.
In the beginning of this book, we said that we will be showing you a way to build Flask applications that can grow and scale with your application. The scalability of a web application is not limited to raw performance, it is also measured by how usable and maintainable the code base is. A big step in maintaining a code base is being able to separate the logic for the configuration of the application itself and the business logic. Once you are able to carefully control the configuration, it also becomes possible to run automated tests, which further improve the quality and usability of a code base.
Most of what we've seen to date involves creating a single file
server.py where we define the application and defining logic within there. We took a big step to improving that with Blueprints in Chapter 3. We'll take another step in that direction in this Chapter by using the "Application Factory" design pattern.
Once we've adopted the application factory pattern, we will be able to take another big step forward in maintainability by introducing automated tests in the next chapter.
What is a factory
The Flask application factory sounds complicated, but it can simply be defined as having a function return a configured instance of a Flask application, instead of instantiating one in the global scope. Traditionally the function is (very creatively) named
Why would you want this? For one thing, you can have arguments for the function that configure the application in a specific way. A common parameter within these
create_app functions is whether or not the application should be configured for production mode or not. One way to use that parameter would be to use that argument to toggle certain blueprints or external services that should not be used in production.
To get started, we're going to create a new folder within our application for our new application factory structure. This folder is typically named whatever your application is called, so for our current example, we can call it
stock_app. This folder is where we are going to create define a set of Python modules (files) for the different components of our application. We can set this folder up as a Python package that can be imported by creating an
__init__.py file within
stock_app. This file is where we're going to define our
We're then going to move the blueprints and templates folder to within the
stock_app folder. Since we're going to move entirely to the application factory pattern, we can delete the
server.py file. We'll recreate it within
At this point your folder structure should look like this.
stock_app/ __init__.py blueprints/ home.py stock.py templates/ .... requirements.txt Procfile
__init__.py, we will start off by creating a
create_app function that takes in no arguments for now.
def create_app(): return ...
The function should return a Flask application object. In order to create a Flask application object, we will need to import Flask at the top of the file just like we have before (
from flask import Flask) and then within the
create_app function, we can initialize an application.
from flask import Flask def create_app(): app = Flask(__name__) return app
Thanks to the
__init__.py file within
stock_app, any Python module in the parent folder of
stock_app could run
from stock_app import create_app to be able to create and start our application.
At this point, we have an extremely simple application factory, but it doesn't actually do anything. There are no routes that have been configured here, so that's what we'll do next.
Our blueprints are defined within the blueprints folder. To import them, you might be tempted to do
from blueprints.home import home but that will cause an error to anyone who runs the application. Python will not recognize that import as a relative import of a package located within stock_app and will error out saying that it couldn't find a package called "blueprints". To mark it as a relative import, we need to prefix it with a dot,
from .blueprints.home import home. Instead of relying on that shortcut, we can go the whole way and specify the full package path so that there is no confusion.
from stock_app.blueprints.home import home
Once we have that imported, we can register the routes for the home and stock blueprints.
from flask import Flask from stock_app.blueprints.home import home from stock_app.blueprints.stock import stock def create_app(): app = Flask(__name__) app.register_blueprint(home) app.register_blueprint(stock) return app
At this point, we can run the application from the parent folder of the stock_app folder.