I'm writing a flask app which has includes another three apps in it! admin, manager and worker. those three has their own folder in project folder. There's also app.py, which gethers ever three apps, and run.py which run the final flask app. but whenever I try to run run.py it goes to an error: can not import name 'db' from partially initialized module 'app'
here's the app.py I've just wrote:
# app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# in-project imports
from config import Config, DB_NAME
from admin_app import create_admin_app
from manager_app import create_manager_app
from worker_app import create_worker_app
db = SQLAlchemy()
def create_app():
# Creates the application
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
from admin_app.models import Admin
from manager_app.models import Manager
from worker_app.models import Worker, Report
# Register Blueprints:
create_admin_app(app)
create_manager_app(app)
create_worker_app(app)
return app
this is the full trackback error:
File "C:\Users\user\Desktop\Shortcuts\3-Other Courses\Flask-Projects\Manager\run.py", line 1, in <module>
from app import create_app
File "C:\Users\user\Desktop\Shortcuts\3-Other Courses\Flask-Projects\Manager\app.py", line 6, in <module>
from admin_app import create_admin_app
File "C:\Users\user\Desktop\Shortcuts\3-Other Courses\Flask-Projects\Manager\admin_app\__init__.py", line 3, in <module>
from .models import Admin
File "C:\Users\user\Desktop\Shortcuts\3-Other Courses\Flask-Projects\Manager\admin_app\models.py", line 1, in <module>
from app import db
ImportError: cannot import name 'db' from partially initialized module 'app' (most likely due to a circular import) (C:\Users\user\Desktop\Shortcuts\3-Other Courses\Flask-Projects\Manager\app.py)
and here's the files mentioned in the trackback:
# __init__.py
from flask import Blueprint
from flask_login import LoginManager
from .models import Admin
admin = Blueprint('admin', __name__, template_folder='templates', static_folder='static')
login_manager = LoginManager()
login_manager.login_view = 'admin.login'
@login_manager.user_loader
def load_user(user_id):
return Admin.query.get(user_id)
def create_admin_app(app):
login_manager.init_app(app)
app.register_blueprint(admin, url_prefix='/admin')
# models.py
from app import db
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
class Admin(db.Model, UserMixin):
__tablename__ = 'admin'
id = db.Column(db.Integer, primary_key=True)
personel_id = db.Column(db.Integer, nullable=False, unique=True)
password = db.Column(db.String(250), nullable=False)
def set_password(self, password):
self.password = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password, password)
def get_by_id(cls, user_id):
return cls.query.filter_by(personel_id=user_id).first()
What you have is a case of circular dependency
not uncommon in your Flask application. Circular imports happen when two or more modules depend on each other, leading to a situation where Python cannot properly initialize the modules.
This I presume is how it occured
In your case, the circular import occurs because:
app.py
-> imports create_admin_app from admin_app.
admin_app/__init__.py
-> imports Admin from admin_app/models.py.
admin_app/models.py
-> imports db from app.py.
You can do this
admin_app/models.py
to import db
only when it's needed.Here is a code snippet to guide you
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config, DB_NAME
from admin_app import create_admin_app
from manager_app import create_manager_app
from worker_app import create_worker_app
db = SQLAlchemy()
def create_app():
# Creates the application
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
# Import models only after db has been initializied
from admin_app.models import Admin
from manager_app.models import Manager
from worker_app.models import Worker, Report
# all Blueprints:
admin_app(app)
manager_app(app)
worker_app(app)
return app
OR
Flask
According to Flask documentation found here: docs
"Flask solves this issue with the application context. Rather than referring to an app directly, you use the current_app proxy, which points to the application handling the current activity. Flask automatically pushes an application context when handling a request."
Here is a code snippet to guide you
admin_app/models.py
from flask import current_app
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
class Admin(UserMixin):
__tablename__ = 'admin'
id = db.Column(db.Integer, primary_key=True)
personel_id = db.Column(db.Integer, nullable=False, unique=True)
password = db.Column(db.String(250), nullable=False)
def set_password(self, password):
self.password = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password, password)
def get_by_id(cls, user_id):
return cls.query.filter_by(personel_id=user_id).first()
@property
def db(self):
return current_app.extensions['sqlalchemy'].db
I would also advise you teardown db connection after by following this code sample below:
from flask import g
def get_db():
if 'db' not in g:
g.db = connect_to_database()
return g.db
@app.teardown_appcontext
def teardown_db(exception):
db = g.pop('db', None)
if db is not None:
db.close()