Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular import of db reference using Flask-SQLAlchemy and Blueprints

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):

application.apps.people.views.py

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() 

application.blueprints.py

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

like image 971
S182 Avatar asked Apr 08 '14 07:04

S182


People also ask

How do I import a database into SQLAlchemy?

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.

What is circular import in Flask?

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.

How does SQLAlchemy connect to Flask?

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.

Can I use SQLAlchemy without Flask?

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.


2 Answers

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:

  • database.py → app.py
  • views.py → app.py
  • database.py → views.py

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 
like image 63
S182 Avatar answered Sep 21 '22 15:09

S182


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.

like image 23
dexity Avatar answered Sep 22 '22 15:09

dexity