我正在使用Flask-SQLAlchemy和Blueprints,我无法使用循环导入。 我知道我可以在函数内部编写导入并使其工作,但这听起来很讨厌,我想与社区确认是否有更好的方法来做到这一点。
问题是我有一个模块(blueprints.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()
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)建议将初始化代码放在方法中,但循环导入仍然存在。
修改 我使用模式Application Factory
修复了问题答案 0 :(得分:43)
我在Application Factory模式的帮助下修复了问题。我在第三个模块中声明了数据库,稍后在我启动应用程序的同一个模块中对其进行配置。
这导致以下导入:
没有循环导入。在调用数据库操作之前,确保启动并配置应用程序非常重要。
以下是一个示例应用程序:
<强> 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
答案 1 :(得分:23)
Flask的循环进口让我疯狂。来自文档:http://flask.pocoo.org/docs/0.10/patterns/packages/
...请注意,这一般是个坏主意,但实际上这很好。
这不好。 这是非常错误的。我还考虑将__init__.py
中的任何代码作为一种不好的做法。它使应用程序难以扩展。蓝图是一种缓解循环导入问题的方法。我认为Flask需要更多这个。
答案 2 :(得分:3)
Serge,在一个名为models.py
的单独文件中引出模型的定义。
在包的__init__.py
文件中注册蓝图。
您已获得循环导入,因为蓝图文件试图从views.py
导入人员引用,但在views.py
您尝试从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
- &gt; mod = Module('app.mods.people', 'people')
people/views.py
- &gt; @mod.route('/page')
app/__init__.py
- &gt; from app.mods import people; from app.mods.people import views; app.register_blueprint(people.mod, **options);
答案 3 :(得分:3)
我知道这已经解决了,但我以稍微不同的方式解决了这个问题,想要回答以防万一。
最初,我的应用程序代码(例如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