Flask Application Factory Imports Done Right

Are you working in a large Flask application and occasionally end up in circular import distress? The way your init.py file handles middleware and extensions plays a big role in your long term maintainability of the code base. Here is a quick example of a pattern that will cause you pain in a large scale codebase and the solution.

This works for a while until it doesn't.

+--project_folder
|    +--__init__.py

# __init__.py
from flask_sqlalchemy import SQLAlchemy
db = db = SQLAlchemy()

def create_app():
    server = Flask(__name__, static_folder='static', static_url_path='/static')
    server.config.from_object('config.Config')
    db.init_app(server)
    with server.app_context():
        db.create_all()

The key for long term and large scale success is to minimize or eliminate project modules that import other project modules. This can be confusing when utilizing the flask application factory pattern but I've found the following structure to be effective in reducing the pain of imports at scale.

# project structure
+--app.py
+--project_folder
|    +--__init__.py
|    +--another_file.py
|    +--project_subfolder
|         +--random_other_project_file.py


# another_file.py
from flask_sqlalchemy import SQLAlchemy
db = db = SQLAlchemy()

---

# __init__.py
from another_file import db

def create_app():
    server = Flask(__name__, static_folder='static', static_url_path='/static')
    server.config.from_object('config.Config')
    db.init_app(server)
    with server.app_context():
        db.create_all()

---

# random_other_project_file.py
import pandas as pd
from project_folder.another_file.py import db

df = pd.DataFrame(columns=["id", "user_name"])
df.to_sql("user_table", con=db.engine)

This pattern allows you to import db from any other project file without concerns to the other imports that are needed in the project init.py file. If you are reading this there is a good chance you've read the excellent articles from Todd Birchard on hackers and slackers regarding Flask. The structure laid out in Todd's tutorial has helped me immensely over my flask journey but once a project reaches a certain scale the imports of any given file become a public enemy. Initialize your application context objects outside the main init.py file and you'll have one less headache than other python devs.