Frontend Backend Split and using Flask without Flask‐SQLAlchemy - SeanGrady/life_tracker GitHub Wiki

While most of the popular tutorials and guides on using Flask assume that you will be using the Flask-SQLAlchemy extension to manage your application's database, I have found this to be insufficient and prefer using Flask and SQLAlchemy separately. This makes it much easier to:

  • Access SQLAlchemy's lower-level interfaces when required
  • Use SQLAlchemy's documentation for database-related issues (the Flask and Flask-SQLAlchemy documentation leaves a lot to be desired, in my opinion)
  • Structure my application the way that makes the most sense for my particular use case
  • Use the database and associated python code in contexts outside the application I'm developing -- for example, fussing around with ML algorithms or statistical analysis in random python scripts

To this end, the backend and flask_app folders are both separate sub-packages, which sometimes necessitates tricky design decisions in cases where functionality is closely tied in with both aspects, like in the case of user authentication.

This results in weirdness like whatever the heck is going on with the flask_login.user_loader function. It can't be in the backend.models.py file, like in many popular flask-login tutorials, because the way I'm implementing it means that it needs to use the contextual session from backend.crud.py, which in turn imports the initialized sqlalchemy.ext.declarative_base() class Base from the backend.models.py file, which causes a circular import. So either the imports need to be scattered all over the file, which is terrible or my user_loader() should be defined in its own file (or in flask_app/__init__.py, which is clearly wrong), but then it never gets run because in those tutorials it was only getting run because AppUser was being imported from models.py which happened to run the rest of models.py as a side effect. This also seems clearly wrong, but splitting into its own file means I have to make sure it gets run somehow, so I have to import its module in the backend sub-package's __init__.py.

None of this is great, and it's one of the reasons that I've switched to using SQLAlchemy's scoped_session() function instead of using contextual_session() from backend.crud.py everywhere (more on that decision here). This allows me to use the flask app's app.session in the user_loader() function, which lets me define it in the auth_bp flask blueprint, but currently means that sessions are thread-local instead of request-local.