I am using Flask-SQLAlchemy and Blueprints and I cannot help myself from using circular imports. I know I can write imports inside functions and make it work but it sounds nasty, I'd like to confirm with the community if there is a better way to do this.
The problem is I have a module (blueprints.py) where I declare the database and import the blueprints but those blueprints need to import the database declaration at the same time.
This is the code (excerpt of the important parts):
from application.blueprints import db people = Blueprint('people', __name__, template_folder='templates', static_folder='static') class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True) @people.route('/all') def all(): users = User.query.all()
from application.apps.people.views import people app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' db = SQLAlchemy(app) app.register_blueprint(people, url_prefix='/people')
I have read the documentation and the questions I found on this topic, but I still cannot find the answer I am looking for. I have found this chapter (https://pythonhosted.org/Flask-SQLAlchemy/contexts.html) where it suggest to put the initialization code inside a method but the circular import still persist.
Edit I fixed the problem using the pattern Application Factory
To do this, we need to open our terminal to our working directory and follow this process: Initialize the Python interpreter. Next, import the database variable from the __init__.py file where we initialized the SQLAlchemy instance of the object, then create the database.
Generally, the Python Circular Import problem occurs when you accidentally name your working file the same as the module name and those modules depend on each other. This way the python opens the same file which causes a circular loop and eventually throws an error.
Step 1 - Install the Flask-SQLAlchemy extension. Step 2 - You need to import the SQLAlchemy class from this module. Step 3 - Now create a Flask application object and set the URI for the database to use. Step 4 - then use the application object as a parameter to create an object of class SQLAlchemy.
This does not completely answer your question, because it does not remove Flask dependency, but you can use SqlAlchemy in scripts and tests by just not running the Flask app. One difficulty you may encounter is the requirement of using db.
I fixed the problem with the help of the Application Factory pattern. I declare the database in a third module and configure it later in the same module in which I start the application.
This results in the following imports:
There is no circular import. It is important to make sure that the application was started and configured before calling database operations.
Here is an example application:
app.py
from database import db from flask import Flask import os.path from views import User from views import people def create_app(): app = Flask(__name__) app.config['DEBUG'] = True app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////tmp/test.db" db.init_app(app) app.register_blueprint(people, url_prefix='') return app def setup_database(app): with app.app_context(): db.create_all() user = User() user.username = "Tom" db.session.add(user) db.session.commit() if __name__ == '__main__': app = create_app() # Because this is just a demonstration we set up the database like this. if not os.path.isfile('/tmp/test.db'): setup_database(app) app.run()
database.py
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy()
views.py
from database import db from flask.blueprints import Blueprint people = Blueprint('people', __name__, template_folder='templates', static_folder='static') class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True) @people.route('/') def test(): user = User.query.filter_by(username="Tom").first() return "Test: Username %s " % user.username
Circular imports in Flask are driving me nuts. From the docs: http://flask.pocoo.org/docs/0.10/patterns/packages/
... Be advised that this is a bad idea in general but here it is actually fine.
It is not fine. It is deeply wrong. I also consider putting any code in __init__.py
as a bad practice. It makes the application harder to scale. Blueprints is a way to alleviate the problem with circular imports. I think Flask needs more of this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With