質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

Q&A

解決済

2回答

12996閲覧

current_app vs app のちがいは?

sequelanonymous

総合スコア123

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

0グッド

3クリップ

投稿2018/08/05 06:31

編集2018/08/05 06:33

current_appの説明がしっくりと理解できません。
flaskでORMを書いていますが、調べながら見よう見まねで動かしつつ、flask-migrateを実行してmigrationファイルができるという状況です。
しかし、ちゃんと理解できていません。とりわけ、current_appについて理解できていません。
current_appを理解するためには、公式ドキュメントの以下の点について理解する必要があると思っています。

  1. まず、なぜproxyの話がでてくるのか? migrationコマンドを実行する時にthe current requestを送っていないと思います。もし、requestをどこかで送っているとしてら、どの部分でそういうコードをかいているのか?

blueprintsは使っていないし、そもそもapplication factory patternという言葉が曖昧で意味がわからないが使っていいないと思うので関係がないと思うが、import itのitは何をさしているのか?

migrationを実行するときに、このアプリケーションを実行するためにたてるサーバーとは別にもう一つmigrationようにサーバーをたててrunしているのか?それは、以下のコードのどの部分で行われているのか?

以下、公式ドキュメントからの抜粋
http://flask.pocoo.org/docs/1.0/api/#flask.current_app

flask.current_app A proxy to the application handling the current request. This is useful to access the application without needing to import it, or if it can’t be imported, such as when using the application factory pattern or in blueprints and extensions. This is only available when an application context is pushed. This happens automatically during requests and CLI commands. It can be controlled manually with app_context(). This is a proxy. See Notes On Proxies for more information.

以下、実際にちゃんと理解せず使ってなんとか動かしている箇所

python

1from flask import Flask 2from flask_sqlalchemy import SQLAlchemy 3from c.config import test 4from flask_migrate import Migrate 5 6current_app = Flask(__name__) 7from c.models.models import db 8current_app.config['JSON_AS_ASCII'] = False 9current_app.config.from_object(test) 10migrate = Migrate(current_app, db) 11 12 13with current_app.app_context(): 14 config.set_main_option('sqlalchemy.url', 15 current_app.config.get('SQLALCHEMY_DATABASE_URI')) 16 target_metadata = db.metadata 17 18... 19... 20... 21 22def run_migrations_online(): 23 """Run migrations in 'online' mode. 24 25 In this scenario we need to create an Engine 26 and associate a connection with the context. 27 28 """ 29 30 # this callback is used to prevent an auto-migration from being generated 31 # when there are no changes to the schema 32 # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html 33 def process_revision_directives(context, revision, directives): 34 if getattr(config.cmd_opts, 'autogenerate', False): 35 script = directives[0] 36 if script.upgrade_ops.is_empty(): 37 directives[:] = [] 38 logger.info('No changes in schema detected.') 39 40 engine = engine_from_config(config.get_section(config.config_ini_section), 41 prefix='sqlalchemy.', 42 poolclass=pool.NullPool) 43 44 connection = engine.connect() 45 context.configure(connection=connection, 46 target_metadata=target_metadata, 47 process_revision_directives=process_revision_directives, 48 **current_app.extensions['migrate'].configure_args) 49 50 try: 51 with context.begin_transaction(): 52 context.run_migrations() 53 finally: 54 connection.close() 55 56if context.is_offline_mode(): 57 run_migrations_offline() 58else: 59 run_migrations_online()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

ピンポイントでコンテキストについて勉強中でしたので、理解の範囲で回答します。
基本的に @tachikoma さんの回答の補助になりますが。。
(参考: http://flask.pocoo.org/docs/1.0/reqcontext/#purpose-of-the-context)

例として、Flask アプリのメインファイル (例: app.py) から他のモジュール (例: db.py) をインポートするケースを考えます。
app.py 内では app = Flask(__name__) にて、Flask アプリを生成します。
db.py は、インポートされることを想定していますので、db.py 内では app を定義しません。ですが、 app.config['SQLALCHEMY_DATABASE_URI'] のように、app.py で生成する app の情報にアクセスするケースがあります。
そこで、app.py から app をインポートしてしまうと、app.py & db.py が双方で app を生成するループができてしまいます。(マニュアルでは circular import issues と言っています)
それを回避するのが current_app です。

current_app は、app の擬似的なもので app のインポートせずに利用できます。なので、app.config['SQLALCHEMY_DATABASE_URI'] は、current_app.config['SQLALCHEMY_DATABASE_URI'] とすることで、app の双方のファイルによる生成ループを回避できます。

ちなみに、添付のコードはメインのファイルでないと思いますので、current_app = Flask(__name__) は削除すべきです。Flask 内の current_app と区別できているようですが、単純にインスタンスが生成されたまま使われていないだけかと思います。

また、
・Flask の context は 2 種類: request context & application context
・request context は、request や session を指す
・application context は、current_app や g を指す
・これらの context は、リクエスト単位のスレッド内で生成・消滅している
(http://flask.pocoo.org/docs/1.0/reqcontext/#purpose-of-the-context )

以上が質問への回答になります。

----- 以下は、まだ腑に落ちない場合にだけお読みください。-----

この時点で、いくつか疑問が残ります。
疑問 1: db.py から app 情報になぜアクセスできないか?
これは、app がグローバルにないからです。

疑問 2: なぜ app がグローバルにないのか?
Flask は複数のアプリを同時に起動できるように設計されているからのようです。
設定の違う同一アプリ、全く違うアプリが起動できるようです。
(詳細な方法はこちらから: http://flask.pocoo.org/docs/1.0/patterns/appdispatch/)

各アプリ情報がグローバルにあるとそれぞれの情報が干渉する可能性がありますが、グローバルにないため、それぞれのアプリが独立して動作できるようになっています。

なので例にあげた db.py から見えるのは、リクエスト毎に生成される app の context (current_app, g, request, session) だけなので、current_app とする必要があります。(でないと "RuntimeError: Working outside of application context." がでます)。

投稿2018/08/07 22:56

tsuBee5

総合スコア21

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sequelanonymous

2018/08/08 15:26

とてもご丁寧にありがとうございます! 質問させてください、app.py から app をインポートしてしまうと、app.py & db.py が双方で app を生成するループができてしまいます。とは、つまり、app.pyファイル内にimport appと書いた場合のことをいっていますか?僕は、app.pyファイル内のapp.config['SQLALCHEMY_DATABASE_URI'] にアクセスするためにimport appとかくことはない気がしていますがどうなんでしょうか?もしくは、db.pyファイル内にimport appとapp.config['SQLALCHEMY_DATABASE_URI']を書いた場合のことをいっていますか? また、”リクエスト毎に生成される app の context (current_app, g, request, session) だけなので”の文脈でのリクエストの意味をおしえていただけませんか?
tsuBee5

2018/08/08 16:45 編集

例えば、下のような例になります。 ``` python # app.py from flask import Flask import db app = Flask(__name__) db.init_app(app) ``` ```python # db.py from flask import current_app from flask_sqlalchemy import SQLAlchemy import app app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db' db = SQLAlchemy() ``` db.pyapp.py をインポート (import app) しないと、app が定義されていないことになるので、エラーがでます。そこで db.pyapp.py をインポート (import app) すると、 0. app.py の ```import db``` 行で db.py をインポート 0. db.py の ```import app``` 行で app.py をインポート が繰り返されます。 (「app.py & db.py が双方で app を生成するループ」ではなく、「インポートしあうループ」が正しかったですね。英文にもそう書いていますし。。すみません。。) リクエストは、HTTP リクエスト (GET, POST など) です。 前の回答者のスレッド読みましたが、疑問にもたれている "current request" は、"http request" であっています。 "current" というのは、複数の人が複数のページ (例: "http://url/" や "http://url/user/") に同時にアクセス (= HTTP リクエスト) するケースを考えるとわかりやすいですが、そのそれぞれの人の HTTP リクエストを "current" と言っています。
sequelanonymous

2018/08/09 05:41

ものすごく腑に落ちました。ご丁寧にありがとうございます!
guest

0

ここで言うproxyはプロクシサーバではなく、app = Flask(__name__)の代理と考えて下さい。blueprintを使った別のファイル(もしくはモジュール)でページを作成したとして、実行コンテキストをいちいちそのモジュールに渡すのは割と面倒です。そんな時に別モジュール側からappに簡単にアクセスする手段としてcurrent_appと言うメソッドが用意されています。

提示されたコードにはcurrent_app = Flask(__name__)とありますが、ここではFlaskが用意しているメソッドと混乱しないようappという変数名にしておくのがいいかと思います。

migrationは触ったことがないので分からないですm(._.)m

投稿2018/08/05 16:17

tachikoma

総合スコア3601

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sequelanonymous

2018/08/06 01:49

ありがとうございます! __init__.pyにも同じapp = Flask(__name__)を書いていますが、そのappに上記記載のファイル(migrationディレクトリのenv.py) にあるapp = Flask(__name__)のappのコンテキストに追加するというイメージでしょうか? もしくは、migrationはmigrationで別でappをrunさせているというイメージでしょうか? もしかしたら、実行コンテキストの意味の私の理解が間違っているかもしれませんのご教示頂きたいです。 ちなみに、A proxy to the application handling the current request.という文頭の一文にある、 current requestとは、なんのことを言っていると思われますか?http requestのrequestとは別の意味な気がしているのですが。 お返事宜しくお願い致します。
tachikoma

2018/08/06 04:17

実行コンテキストはまずい表現で、Flaskのドキュメントにあるのは大きく分けてRequest contextとApplication contextでした。すみません。 件のcurrent_appはRequest contextの中からApplication contextを知るためのproxy(appの代理、という意味)だと思います。Application contextが分かると、(DBの情報などを持っている)configにアクセスできるようになります。
tachikoma

2018/08/06 04:18

あと、ちょっと自信ありませんが一つのアプリケーションの中にapp = Flask(__name__)が2つ以上あるのは普通じゃないような・・・。
sequelanonymous

2018/08/06 06:47

ありがとうございます!徐々に理解できてきました。 多分、以下の部分がわかれば僕の中で腑に落ちるかもしれません。 > current requestはクライアントからのhttp requestや、CLIからのコマンドが含まれると思います。 CLIからのコマンドもrequestと言うのは、例えば、flask db migrate みたいなコマンドもrequestというものになるのでしょうか?だとしたら、どういう仕組みか気になります。 恐らく、この記事に答えが書いてありますが、腑に落ちないです。 http://flask.pocoo.org/docs/1.0/cli/ 僕の中ではhttp requestつまりcurlコマンドでurl指定してアクセスしてrequestを送るか、クライアントからrequestが送られてくるというrequestというので全てだと思っていました。 また、Application contextとは、以下の定義とされていますが、the application-level data というのが具体的に何をさすのか、ご存知でしたらご教示頂きたいです。 The application context keeps track of the application-level data during a request, CLI command, or other activity. 上記二点がわかれば、全てがクリアになるのかなと思っています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問