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 )を見つけました。初期化コードをメソッド内に置くことをお勧めしますが、循環インポートは引き続き持続します。
Editパターンを使用して問題を修正しました Application Factory
Application Factory パターンを使用して問題を修正しました。データベースを3番目のモジュールで宣言し、後でアプリケーションを起動する同じモジュールで構成します。
これにより、次のインポートが行われます。
循環インポートはありません。データベース操作を呼び出す前に、アプリケーションが起動および構成されていることを確認することが重要です。
次にアプリケーションの例を示します。
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
Flaskでの循環インポートは私を狂わせています。ドキュメントから: http://flask.pocoo.org/docs/0.10/patterns/packages/
...これは一般的には悪い考えですが、ここでは実際には問題ありません。
元気ではありません。 それはひどく間違っています。__init__.py
悪い習慣として。アプリケーションのスケーリングが困難になります。ブループリントは、循環インポートの問題を軽減する方法です。 Flaskはこれがもっと必要だと思います。
私はこれがすでに解決されていることを知っていますが、私はこれを少し異なる方法で解決し、他の人を助けるために答えたいと思いました。
もともと、私のアプリケーションコード(例:my_app.py
)には次の行がありました。
db = SQLAlchemy(app)
そして、私のmodels.py
には、
from my_app import db
class MyModel(db.Model):
# etc
したがって、my_app
でMyModel
を使用する場合の循環参照。これを更新して、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
サージ、_models.py
_と呼ばれる別のファイルでモデルの定義を引き出します。パッケージの___init__.py
_ファイルにブループリントを登録します。
ブループリントファイルが_views.py
_から人の参照をインポートしようとしているため、循環インポートされていますが、_views.py
_では_blueprints.py
_からdbをインポートしようとしています。そして、これらすべてはモジュールのトップレベルで行われます。
次のようにプロジェクト構造を作成できます。
_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
_
PD:
タンクにいる人のために:
_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);