Что я могу сделать с сообщением об ошибке «невозможно импортировать частично инициализированный модуль»?

Я пишу приложение-флягу, в которое входят еще три приложения! администратор, менеджер и работник. у этих троих есть своя папка в папке проекта. Также есть 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()

Пожалуйста, опубликуйте минимально воспроизводимый пример в редактировании. Нам нужно увидеть файл, который на самом деле вызывает ошибку (то есть тот, который импортируется из app.py), а также все пользовательские сценарии, которые вы используете. Кроме того, опубликуйте полное сообщение об ошибке, включая полную обратную связь. Но обязательно сократите все, чтобы уменьшить объем кода, который нам приходится анализировать — так нам будет легче написать хорошие ответы на ваш вопрос!

Anerdw 18.08.2024 09:09
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

У вас есть случай 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.

Ты можешь сделать это

  1. Переместите импорт базы данных внутри выбранной вами именованной функции. измените 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

ИЛИ

  1. Использование переключения контекста в 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 и который должен содержать необходимые атрибуты и методы (РЕКОМЕНДУЕТСЯ).

Но в качестве временного решения вы можете импортировать классы внутри методов, где они фактически используются, а не сверху (НЕ РЕКОМЕНДУЕТСЯ).

Другие вопросы по теме