73

ブループリントを使用してFlaskで「モジュラーアプリケーション」を作成しようとしています。

ただし、モデルを作成するときに、dbFlask-SQLAlchemyによって提供されるオブジェクトを取得するためにアプリを参照する必要があるという問題が発生しています。複数のアプリでいくつかのブループリントを使用できるようにしたいので(Djangoアプリの使用方法と同様)、これは適切なソリューションではありません。*

  • switcharooを実行し、ブループリントにdbインスタンスを作成させることができます。インスタンスは、アプリが残りのブループリントと一緒にインポートします。ただし、モデルを作成したい他のブループリントは、アプリではなく、そのブループリントからインポートする必要があります。

したがって、私の質問は次のとおりです。

  • 後で使用されているアプリを意識せずにブループリントにモデルを定義させ、複数のブループリントをまとめる方法はありますか?これは、ブループリントからアプリモジュール/パッケージをインポートする必要があることを意味します。
  • 私は最初から間違っていますか?ブループリントは、アプリから独立して再配布可能であることを意図していませんか(àlaDjangoアプリ)?
    • そうでない場合は、そのようなものを作成するためにどのパターンを使用する必要がありますか?フラスコ拡張?単純にそれを行うべきではありません-そして多分すべてのモデル/スキーマをRubyonRailsで一元化するのでしょうか?

編集declarative_base():私は今これについて自分で考えていましたが、モデルを宣言するときに持っている必要があるため、これはFlaskよりもSQLAlchemyに関連している可能性があります。そして、それはとにかくどこかから来なければなりません!

おそらく最善の解決策は、Ruby on Railsのように、プロジェクトのスキーマを1つの場所で定義し、それを分散させることです。宣言型SQLAlchemyクラス定義は、実際にはDjangoのmodels.pyよりもschema.rbに似ています。これにより、( alembicまたはsqlalchemy-migrateからの)移行も簡単に使用できるようになると思います。


例を提供するように求められたので、簡単なことをしましょう。データベースに保存されている単純な「静的」コンテンツである「フラットページ」を説明する青写真があるとします。ショートネーム(URL用)、タイトル、本文のみのテーブルを使用します。これはsimple_pages/__init__.py

from flask import Blueprint, render_template
from .models import Page

flat_pages = Blueprint('flat_pages', __name__, template_folder='templates')

@flat_pages.route('/<page>')
def show(page):
    page_object = Page.query.filter_by(name=page).first()
    return render_template('pages/{}.html'.format(page), page=page_object)

次に、このブループリントに独自のモデルを定義させるとよいでしょう(これはsimple_page/models.py):

# TODO Somehow get ahold of a `db` instance without referencing the app
# I might get used in!

class Page(db.Model):
    name = db.Column(db.String(255), primary_key=True)
    title = db.Column(db.String(255))
    content = db.Column(db.String(255))

    def __init__(self, name, title, content):
        self.name = name
        self.title = title
        self.content = content

この質問は以下に関連しています:

dbその他にもさまざまですが、すべての返信はアプリのインスタンスをインポートするか、その逆を行うことに依存しているようです。「大規模なアプリのハウツー」ウィキページでも、「アプリを設計図にインポートする」パターンが使用されています。

*公式ドキュメントには、ブループリントが「含まれている」アプリを気にせずにルート、ビュー、テンプレート、アセットを作成する方法が示されているため、ブループリントは通常、アプリ間で再利用できるはずです。ただし、このモジュール性は、独立したモデルがなければそれほど有用ではないようです

ブループリントはアプリに複数回フックされる可能性があるため、ブループリントにモデルを含めるのは単に間違ったアプローチである可能性がありますか?

4

3 に答える 3

41

私が思うに、最も正しい答えは、モジュラー ブループリント自体がデータ アクセスに直接関係するのではなく、互換性のある実装を提供するアプリケーションに依存するべきだということです。

あなたの例の青写真を考えてみましょう。

from flask import current_app, Blueprint, render_template

flat_pages = Blueprint('flat_pages', __name__, template_folder='templates')

@flat_pages.record
def record(state):
    db = state.app.config.get("flat_pages.db")

    if db is None:
        raise Exception("This blueprint expects you to provide "
                        "database access through flat_pages.db")

@flat_pages.route('/<page>')
def show(page):
    db = current_app.config["flat_pages.db"]
    page_object = db.find_page_by_name(page)
    return render_template('pages/{}.html'.format(page), page=page_object)

このことから、デフォルトの実装を提供することを妨げるものは何もありません。

def setup_default_flat_pages_db(db):
    class Page(db.Model):
        name = db.Column(db.String(255), primary_key=True)
        title = db.Column(db.String(255))
        content = db.Column(db.String(255))

        def __init__(self, name, title, content):
            self.name = name
            self.title = title
            self.content = content

    class FlatPagesDBO(object):
        def find_page_by_name(self, name):
            return Page.query.filter_by(name=name).first()

    return FlatPagesDBO()

そして、あなたの構成で。

app.config["flat_pages.db"] = setup_default_flat_pages_db(db)

上記は、db.Model からの直接の継承に依存せず、代わりに sqlalchemy からのバニラの declarative_base を使用することでよりクリーンにすることができますが、これはその要点を表す必要があります。

于 2012-11-17T16:22:06.123 に答える
0

「ブループリントは、アプリから独立して再配布可能 (Django アプリのように) することを意図したものではありませんか?」と尋ねました。

答えはイエスです。ブループリントは Django アプリとは異なります。

異なるアプリ/構成を使用する場合は、ブループリントではなく「アプリケーション ディスパッチ」を使用する必要があります。これを読んでください [1]: http://flask.pocoo.org/docs/patterns/appdispatch/#app-dispatch [1]

また、ここのリンク [1] http://flask.pocoo.org/docs/blueprints/#the-concept-of-blueprints [1]

「Flask のブループリントは、実際にはアプリケーションではないため、プラグイン可能なアプリではありません。複数回でも、アプリケーションに登録できる操作のセットです。なぜ複数のアプリケーション オブジェクトを持たないのですか?それを行います (アプリケーションのディスパッチを参照してください) が、アプリケーションは個別の構成を持ち、WSGI レイヤーで管理されます。"

于 2012-10-25T20:37:54.470 に答える