Циркулярный импорт ссылки db с использованием Flask-SQLAlchemy и чертежей
Я использую Flask-SQLAlchemy и Blueprints, и я не могу помочь себе использовать циклический импорт.
Я знаю, что я могу писать импорт внутри функций и заставить работать, но это звучит неприятно, я бы хотел подтвердить сообщество, если есть лучший способ сделать это.
Проблема заключается в том, что у меня есть модуль (blueprints.py), где я объявляю базу данных и импортирую чертежи, но эти чертежи должны одновременно импортировать объявление базы данных.
Это код (выдержка из важных частей):
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')
Я прочитал документацию и вопросы, которые я нашел по этой теме, но я все еще не могу найти ответ, который я ищу.
Я нашел эту главу (https://pythonhosted.org/Flask-SQLAlchemy/contexts.html), где предлагается поместить код инициализации внутри метода, но циклический импорт все еще сохраняется.
Edit
Я исправил проблему, используя шаблон Приложение Factory
Ответы
Ответ 1
Я исправил проблему с помощью Application Factory. Я объявляю базу данных в третьем модуле и настраиваю ее позже в том же модуле, в котором я запускаю приложение.
Это приводит к следующим импортам:
- database.py → app.py
- views.py → app.py
- database.py → views.py
Нет циклического импорта. Важно убедиться, что приложение было запущено и настроено перед вызовом операций с базой данных.
Вот пример приложения:
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
Ответ 2
Циркулярный импорт в колбе приводит меня в орехи. Из документов: http://flask.pocoo.org/docs/0.10/patterns/packages/
... Имейте в виду, что это плохая идея в целом, но здесь она на самом деле прекрасна.
Это не нормально. Глубоко неправильно. Я также считаю, что любой код в __init__.py
является плохой практикой. Это делает приложение сложнее масштабировать. Чертежи - это способ облегчить проблему с помощью циркулярного импорта. Я думаю, что Флану нужно больше этого.
Ответ 3
Серж, выведите определение моделей в отдельный файл под названием models.py
.
Запишите проект в файле __init__.py
пакета.
У вас есть циклический импорт, потому что файл чертежа пытается импортировать ссылку на людей из views.py
, но в views.py
вы пытаетесь импортировать db из blueprints.py
. И все это делается на верхнем уровне модулей.
Вы можете сделать свою структуру проекта следующим образом:
app
__init__.py # registering of blueprints and db initialization
mods
__init__.py
people
__init__.py # definition of module (blueprint)
views.py # from .models import User
models.py # from app import db
UPD:
Для тех, кто находится в танке:
people/__init__.py
→ mod = Module('app.mods.people', 'people')
people/views.py
→ @mod.route('/page')
app/__init__.py
→ from app.mods import people; from app.mods.people import views; app.register_blueprint(people.mod, **options);
Ответ 4
Я знаю, что это уже решено, но я решил это немного по-другому и хотел ответить, если это поможет другим.
Первоначально код моего приложения (например, my_app.py
) содержал my_app.py
строку:
db = SQLAlchemy(app)
И вот в моем models.py
меня было:
from my_app import db
class MyModel(db.Model):
# etc
отсюда циклические ссылки при использовании MyModel
в my_app
. Я обновил это так, чтобы models.py имел это:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # note no "app" here, and no import from my_app above
class MyModel(db.Model):
# etc as before
а затем в my_app
:
from models import db, MyModel # importing db is new
# ...
db.init_app(app) # call init_app here rather than initialising db here