Я пишу приложение-флягу, в которое входят еще три приложения! администратор, менеджер и работник. у этих троих есть своя папка в папке проекта. Также есть app.py, который объединяет все три приложения, и run.py, который запускает последнее приложение Flask. но всякий раз, когда я пытаюсь запустить run.py, возникает ошибка: невозможно импортировать имя «db» из частично инициализированного модуля «app»
вот app.py, который я только что написал:
# 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
это полная ошибка трекбэка:
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)
и вот файлы, упомянутые в трекбеке:
# __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()
У вас есть случай circular dependency
, не редкий в вашем приложении Flask. Циклический импорт происходит, когда два или более модулей зависят друг от друга, что приводит к ситуации, когда Python не может правильно инициализировать модули.
Я полагаю, именно так это и произошло
В вашем случае циклический импорт происходит потому, что:
app.py
-> импортирует create_admin_app из admin_app.
admin_app/__init__.py
-> импортирует администратора из admin_app/models.py.
admin_app/models.py
-> импортирует базу данных из app.py.
Ты можешь сделать это
admin_app/models.py
, чтобы импортировать db
только тогда, когда это необходимо.Вот фрагмент кода, который поможет вам
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
ИЛИ
Flask
Согласно документации Flask, которую можно найти здесь: docs
«Flask решает эту проблему с помощью контекста приложения. Вместо того, чтобы напрямую обращаться к приложению, вы используете прокси-сервер current_app, который указывает на приложение, обрабатывающее текущую активность. Flask автоматически передает контекст приложения при обработке запроса».
Вот фрагмент кода, который поможет вам
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
Я бы также посоветовал вам разорвать соединение с базой данных, выполнив следующий пример кода:
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()
Эта проблема обычно возникает, когда в вашем коде есть циклическая зависимость.
Например:
Допустим, у вас есть два класса в вашем проекте: класс A и класс B, каждый из которых находится в файлах A.py и B.py соответственно:
# A.py
class A:
pass
# B.py
class B:
pass
Теперь вам потребовались некоторые атрибуты и методы класса A в классе B, поэтому вы импортировали класс A в файл B.py. Никаких проблем, до сих пор все работает нормально. Теперь, через некоторое время, вы понимаете, что вам нужны некоторые атрибуты и методы класса B в вашем классе A, поэтому на этот раз вы импортировали класс B в A.py, что привело к циклической зависимости.
Чтобы полностью решить эту проблему, вам нужен третий класс C, который будет использоваться A и B и который должен содержать необходимые атрибуты и методы (РЕКОМЕНДУЕТСЯ).
Но в качестве временного решения вы можете импортировать классы внутри методов, где они фактически используются, а не сверху (НЕ РЕКОМЕНДУЕТСЯ).
Пожалуйста, опубликуйте минимально воспроизводимый пример в редактировании. Нам нужно увидеть файл, который на самом деле вызывает ошибку (то есть тот, который импортируется из app.py), а также все пользовательские сценарии, которые вы используете. Кроме того, опубликуйте полное сообщение об ошибке, включая полную обратную связь. Но обязательно сократите все, чтобы уменьшить объем кода, который нам приходится анализировать — так нам будет легче написать хорошие ответы на ваш вопрос!