20

データベースに接続するアプリケーションを作成しています。そのデータベース接続を一度作成してから、アプリケーションの存続期間中その接続を再利用したいと考えています。

また、ユーザーを認証したいと考えています。ユーザーの認証は、リクエストの存続期間中のみ存続します。

フラスコアプリの存続期間中に保存されたオブジェクトと、リクエストに固有のオブジェクトを区別するにはどうすればよいですか? すべてのモジュール (および後続のブループリント) がそれらにアクセスできるようにするには、それらをどこに保存しますか?

これが私のサンプルアプリです:

from flask import Flask, g

app = Flask(__name__)

@app.before_first_request
def setup_database(*args, **kwargs):
    print 'before first request', g.__dict__
    g.database = 'DATABASE'
    print 'after first request', g.__dict__

@app.route('/')
def index():
    print 'request start', g.__dict__
    g.current_user = 'USER'
    print 'request end', g.__dict__

    return 'hello'

if __name__ == '__main__':
    app.run(debug=True, port=6001)

これ (Flask 0.10.1) を実行して に移動するとhttp://localhost:6001/、コンソールに次のように表示されます。

$ python app.py 
 * Running on http://127.0.0.1:6001/
 * Restarting with reloader

before first request {}
after first request {'database': 'DATABASE'}
request start {'database': 'DATABASE'}
request end {'current_user': 'USER', 'database': 'DATABASE'}
127.0.0.1 - - [30/Sep/2013 11:36:40] "GET / HTTP/1.1" 200 -

request start {}
request end {'current_user': 'USER'}
127.0.0.1 - - [30/Sep/2013 11:36:41] "GET / HTTP/1.1" 200 -

つまり、最初のリクエストは期待どおりに機能しflask.gています。データベースを保持しており、リクエストが開始されると、ユーザーの情報も含まれています。

しかし、私の 2 回目のリクエストで、flask.g は完全に削除されました。私のデータベースがどこにも見つかりません。

今、flask.gリクエストのみに適用されていたことがわかりました。しかし、(0.10 の時点で) アプリケーションにバインドされたので、単一の要求だけでなく、アプリケーション全体に変数をバインドする方法を知りたいです。

私は何が欠けていますか?

編集:私は特に MongoDB に興味があります。私の場合は、複数の Mongo データベースへの接続を維持しています。__init__.pyそれらの接続を作成してそれらのオブジェクトを再利用するのが私の最善の策ですか?

4

3 に答える 3

32

flask.gリクエストの期間中だけ物を保存します。ドキュメントでは、値はリクエストではなくアプリケーション コンテキストに格納されると記載されていましたが、これは実装の問題です。オブジェクトflask.gが同じスレッドでのみ使用可能であるという事実は変わりません。単一の要求。

たとえば、データベース接続に関する公式チュートリアル セクションでは、接続はリクエストの開始時に 1 回行われ、リクエストの最後で終了します。

もちろん、本当に必要な場合は、データベース接続を一度作成して に保存し、__init__.py必要に応じて (グローバル変数として) 参照することもできます。ただし、これを行うべきではありません。接続が閉じたりタイムアウトしたりする可能性があり、複数のスレッドで接続を使用できません。

Python で Mongo を使用する方法を指定しなかったので、PyMongoを使用することになると思います。PyMongoがすべての接続プールを処理するからです。

この場合、あなたはこのようなことをします...

from flask import Flask
from pymongo import MongoClient
# This line of code does NOT create a connection
client = MongoClient()

app = Flask()

# This can be in __init__.py, or some other file that has imported the "client" attribute
@app.route('/'):
def index():
    posts = client.database.posts.find()

必要に応じて、このようなことを行うことができます...

from flask import Flask, g
from pymongo import MongoClient
# This line of code does NOT create a connection
client = MongoClient()

app = Flask()

@app.before_request
def before_request():
    g.db = client.database

@app.route('/'):
def index():
    posts = g.db.posts.find()

これは実際にはそれほど違いはありませんが、すべてのリクエストで実行したいロジックに役立ちます (g.dbログインしているユーザーに応じて特定のデータベースに設定するなど)。

最後に、Flask を使用して PyMongo をセットアップする作業のほとんどは、おそらくFlask-PyMongoで行われることがわかります。

あなたの他の質問は、ログインしているユーザーに固有のものを追跡する方法に関するものです。この場合、接続に固執するデータを保存する必要があります。flask.g再クエストの最後にクリアされるのでダメです。

使用したいのはsessionsです。これは、(デフォルトの実装では) ユーザーのブラウザーの Cookie に保存される値を保存できる場所です。Cookie は、ユーザーのブラウザーが Web サイトに対して行うすべての要求と共に渡されるため、セッションに入力したデータを利用できます。

ただし、セッションはサーバーに保存されないことに注意してください。これは、ユーザーにやり取りされる文字列に変換されます。したがって、DB 接続などを格納することはできません。代わりに識別子 (ユーザー ID など) を保存します。

ユーザー認証が正しく機能することを確認するのは非常に困難です。確認する必要があるセキュリティ上の懸念は、驚くほど複雑です。これを処理するには、 Flask-Login のようなものを使用することを強くお勧めします。必要に応じて他のアイテムを保存するために引き続き使用することもsession、Flask-Login にユーザー ID の決定を処理させて、必要な値をデータベースに保存し、すべてのリクエストでデータベースからそれらを取得することもできます。

つまり、要約すると、やりたいことを行うにはいくつかの異なる方法があります。それぞれ用途があります。

  • グローバルは、スレッドセーフな項目 (PyMongo の MongoClient など) に適しています。
  • flask.gリクエストの有効期間中にデータを保存するために使用できます。after_requestSQLAlchemy ベースのフラスコ アプリで行う一般的なことは、メソッドを使用してリクエストの最後にすべての変更が一度に行われるようにすることです。このようなものに使用flask.gすると非常に役立ちます。
  • Flasksessionを使用して、同じユーザーからの後続の要求で使用できる単純なデータ (接続オブジェクトではなく、文字列と数値) を格納できます。これは Cookie の使用に完全に依存しているため、いつでもユーザーが Cookie を削除でき、「セッション」内のすべてが失われます。したがって、セッション内のユーザーに関連するデータを識別するために使用されるセッションを使用して、多くのデータをデータベースに保存することをお勧めします。
于 2013-09-30T20:29:05.747 に答える
4

「アプリケーションにバインドされている」とは、あなたが思っていることを意味するものではありません。これはg、現在実行中のリクエストにバインドされていることを意味します。ドキュメントを引用します。

Flask は、アクティブなリクエストに対してのみ有効であり、リクエストごとに異なる値を返す特別なオブジェクトを提供します。

Flask のチュートリアルでは具体的にはデータベース オブジェクトを永続化しないことに注意してください。うさぎの穴に飛び込むことに本当に興味がある場合は、データベース接続プーリング ツールをお勧めします。(これなど、上記のSOの回答参照で言及されています)

于 2013-09-30T15:59:09.830 に答える
1

セッションを使用してユーザー情報を管理することをお勧めします。セッションは、複数のリクエストに対して情報を保持するのに役立ち、フラスコはすでにセッション フレームワークを提供しています。

from flask import session
session['usename'] = 'xyz'

拡張機能Flask-Loginを見てください。ユーザー認証を処理するように適切に設計されています。

データベースについては、 Flask-SQLAlchemy拡張機能を検討することをお勧めします。これにより、すぐに使用できるように、初期化、プーリング、ティアダウンなどが処理されます。構成でデータベース URI を定義し、それをアプリケーションにバインドするだけです。

from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
于 2013-09-30T16:16:03.287 に答える