web-dev-qa-db-ja.com

Flask-SQLAlchemyとBlueprintsを使用したdb参照の循環インポート

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パターンを使用して問題を修正しました Application Factory

35
S182

Application Factory パターンを使用して問題を修正しました。データベースを3番目のモジュールで宣言し、後でアプリケーションを起動する同じモジュールで構成します。

これにより、次のインポートが行われます。

  • 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
53
S182

Flaskでの循環インポートは私を狂わせています。ドキュメントから: http://flask.pocoo.org/docs/0.10/patterns/packages/

...これは一般的には悪い考えですが、ここでは実際には問題ありません。

元気ではありません。 それはひどく間違っています。__init__.py悪い習慣として。アプリケーションのスケーリングが困難になります。ブループリントは、循環インポートの問題を軽減する方法です。 Flaskはこれがもっと必要だと思います。

24
dexity

私はこれがすでに解決されていることを知っていますが、私はこれを少し異なる方法で解決し、他の人を助けるために答えたいと思いました。

もともと、私のアプリケーションコード(例:my_app.py)には次の行がありました。

db = SQLAlchemy(app)

そして、私のmodels.pyには、

from my_app import db

class MyModel(db.Model):
    # etc

したがって、my_appMyModelを使用する場合の循環参照。これを更新して、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
5
Sam

サージ、_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);

3
Mike