0

I have a simple Flask demo app (Python 3) containing some top level app initialisation code, and a blueprint that just sets/unsets some boolean flags. The structure looks like this:

flaskery
├── config.py
├── flaskery
│   ├── app.py           - application init code (create app, db)
│   ├── __init__.py      - empty
│   ├── __main__.py      - entry point
│   └── switches
│       ├── state.py     - db structure
│       ├── switches.py  - control code
│       └── templates
│           └── (template stuff)
└── setup.py

The app.py file contains the application initialisation code, including:

app = Flask(__name__)

# Note: Alchy has the same interface as flask.ext.sqlalchemy.SQLAlchemy,
# except that the model is less coupled to flask.
db = Alchy(app, Model=SwitchesState)

# Circular dependency!
from flaskery.switches.switches import switches_app

app.register_blueprint(switches_app)

db.create_all()

However, the blueprint code contains:

from flaskery.app import db

...so that it can do things like, eg.

switches_app = Blueprint('switches', __name__, url_prefix='', template_folder='templates')

@switches_app.route("/")
def root():
    # SwitchesState is your run-of-the-mill SQL schema defined as
    # a class.
    state = SwitchesState()

    # Do things that include, say...
    db.session.add(state)
    db.session.commit()

    # etc.

    template = render_template(...)
    return template

I don't like this circular dependency. I would prefer the blueprint to only need to know about the interface required to manipulate the DB session (if at all), and not need to import already-initialised objects from the top level. Making the top level app code not rely on import order is another goal. I'd also like to avoid relying on a global in control code (although Flask's "session" and "request" globals kind of scuttle that, but less of that would be good).

Is there a way to break this circular dependency and still use Flask?

detly
  • 29,332
  • 18
  • 93
  • 152
  • You know, if there was a way to tell the `SwitchState` object to add/commit itself, or if Flask could do that whenever necessary, I wouldn't even need to import the active DB session. – detly Jul 10 '15 at 02:22
  • 1
    This looks like a duplicate - if the above question (or [this one](http://stackoverflow.com/questions/22929839/circular-import-of-db-reference-using-flask-sqlalchemy-and-blueprints)) don't answer your questions, just edit and ping me and I'll vote to re-open :-) – Sean Vieira Jul 10 '15 at 03:02
  • @SeanVieira Not quite a duplicate, but had enough info to get me started. I've already solved the model/app cycle using [alchy](https://github.com/dgilland/alchy)/[flask-alchy](https://github.com/dgilland/flask-alchy). But I realised there are two ways to do what I need. The method suggested in the linked Q implies creating the DB object in the controller code. This is kind of nice because it means the app setup code only needs to import from the blueprint module, not the model module. I'm not sure about other effects on the database though. – detly Jul 10 '15 at 03:43
  • The second way is to keep the DB creation in `app.py`, but use `state.save()` and `state.session().commit()` in the controller. This means that you can keep your DB init code with all the other init code, which might be neater depending on what your initialisation involves. – detly Jul 10 '15 at 03:44

0 Answers0