TL; DR: Как использовать объект metadata
из Blueprint для создания экземпляра Flask-SQLAlchemy? Единственное место, где я могу предоставить декларативный базовый объект metadata
, - это начальный вызов SQLAlchemy()
. Но когда я импортирую его из Blueprint в моем файле extensions.py
, для кода Blueprint требуется объект db
, и загрузка не удалась из-за циклического импорта.
У меня есть несколько классов моделей, которые я хотел бы использовать как внутри, так и вне Flask. Для этого я использую декларативный метод , и мое приложение настроено на использование модели App Factory и Blueprints. Регистрация моделей в SQLAlchemy осуществляется с помощью аргумента metadata
при создании объекта db
. В контексте моего приложения имеет смысл объявить объект metadata
в Blueprint, а не в основном приложении Blueprint. (Это - то, где большая часть кода, который ссылается на это, включая сценарий утилиты не Flask, используемый для начального заполнения базы данных.) Однако импорт класса модели из второго Blueprint заканчивается циклическим импортом.
$ flask db migrate
Error: While importing "my_app", an ImportError was raised:
Traceback (most recent call last):
File "my_app/venv/lib/python3.7/site-packages/flask/cli.py", line 235, in locate_app
__import__(module_name)
File "my_app/my_app.py", line 1, in <module>
from app import create_app
File "my_app/app/__init__.py", line 7, in <module>
from app.extensions import *
File "my_app/app/extensions.py", line 10, in <module>
from turf.models import metadata
File "my_app/turf/__init__.py", line 1, in <module>
from .routes import bp
File "my_app/turf/routes.py", line 14, in <module>
from app.extensions import db
ImportError: cannot import name 'db' from 'app.extensions' (my_app/app/extensions.py)
Как уже упоминалось в этом общем вопросе о циклическом импорте для Blueprints, решение, которое работает, заключается в том, чтобы импортировать объект db
изнутри каждой функции во втором Blueprint, таким образом обойдя импорт при инициализации файла extensions.py
. Но кроме того, что надоедает, это просто невероятно.
В идеале я бы мог передать созданный мною объект metadata
методу init_app()
SQLAlchemy. Это решило бы эту проблему одним махом. К сожалению, init_app()
не принимает аргумент metadata
. Есть ли другой способ регистрации метаданных с экземпляром SQLAlchemy после инициализации? Или я пропустил какой-то другой ключевой элемент подхода декларативной модели?
Я должен сказать, что часть, не относящаяся к колбе, работает просто отлично. Мой служебный скрипт может импортировать модели и использовать их для добавления объектов в базу данных. Только импорт фляги доставляет мне неприятности.
Вот иерархия:
.
├── app
│ ├── __init__.py
│ └── extensions.py
└── turf
├── __init__.py
├── models.py
└── routes.py
И соответствующий код, который не работает из-за циклического импорта:
приложение / __ init__.py:
from app.extensions import *
def create_app():
app = Flask(__name__)
with app.app_context():
import turf
app.register_blueprint(turf.bp)
db.init_app(app)
приложение / extensions.py:
from turf.models import metadata
db = SQLAlchemy(metadata=metadata)
дерн / __ init__.py:
from .routes import bp
дерн / models.py:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import MetaData
metadata = MetaData()
Base = declarative_base(metadata=metadata)
# All the turf models are declared in this file
class Boundary(Base):
# ...etc...
дерн / routes.py:
from .models import *
from app.extensions import db
bp = Blueprint('Turf', __name__, url_prefix='/turf')
@bp.route('/')
def index():
return render_template('turf/index.html')