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

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

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

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

Python 3.x

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

Q&A

解決済

FlaskにおいてModelとViewとDB設定をうまくファイル分離できない

MagMag
MagMag

総合スコア79

Flask

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

Python 3.x

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

1回答

0グッド

1クリップ

427閲覧

投稿2022/11/27 00:42

編集2022/11/28 02:50

前提

Python+Flaskで簡易なWebページを作成しています。

状況

  • Flaskにおいて、ModelとViewとDB設定をファイル単位で分割したい。
  • ViewとDBを共通化したファイル(「うまくいくコード」のsub.py)ではflaskのcurrent_appをモジュールを利用して、applicationの設定情報を読み込める。
  • しかし、sub.pyのうち、DBクラスを分割した場合、DBクラス内でapplication.configの読み込み方がわかりません。
  • 実際のコードで、DBクラスではAWSのDynamoDBへの接続情報をapplication.configから読み込もうとしています。事例を検索するとSQLAlchemyでのDB分割方法はありましたが、このスクリプトでSQLAlchemyは使用していません。そのため、db.init_app(app)といった利用ができない状況です。

うまくいくコード

main.py

Python

1from flask import Flask 2from sub import application_sub 3 4def create_app(): 5 application = Flask(__name__) 6 application.config['table_name'] = 'fuga_table' 7 return application 8 9 10if __name__ == '__main__': 11 application = create_app() 12 application.register_blueprint(application_sub) 13 application.run()

sub.py

Python

1from flask import Blueprint, current_app 2 3application_sub = Blueprint('sub', __name__) 4 5class DB(): 6 table_name = current_app.config['table_name'] 7 8@application_sub.route('/') 9def top_page(): 10 return 'hello world'

試したこと(うまくいかないコード)

以下のコードでmain.pyを実行すると、RuntimeError: Working outside of application context.
とエラーが出ます。sub2でapplication設定を読めないのはわかるのですが、対応の仕方がわかりませんでした。

main.py(変更なし)

Python

1from flask import Flask 2from sub import application_sub 3 4def create_app(): 5 application = Flask(__name__) 6 application.config['table_name'] = 'fuga_table' 7 return application 8 9 10if __name__ == '__main__': 11 application = create_app() 12 application.register_blueprint(application_sub) 13 application.run()

sub.py(DB設定を除外)

Python

1from flask import Blueprint, current_app 2from sub2 import DB 3 4application_sub = Blueprint('sub', __name__) 5 6@application_sub.route('/') 7def top_page(): 8 return 'hello world'

sub2.py(DB設定)

Python

1from flask import current_app 2 3class DB(): 4 table_name = current_app.config['table_name']

実際のDBファイルのイメージ

実際のDBは以下のようになっています。

DB

Python

1from pynamodb.models import Model 2from pynamodb.attributes import UnicodeAttribute 3 4class DB(Model): 5 class Meta: 6 table_name = application.config.get('TABLE_NAME') 7 region = application.config.get('AWS_REGION') 8 aws_access_key_id = application.config.get('AWS_ACCESS_KEY_ID') 9 aws_secret_access_key = application.config.get('AWS_SECRET_ACCESS_KEY') 10 11 partition_key = UnicodeAttribute(hash_key=True, null=False)

View

Python

1from sub import DB 2 3@application.route('/', methods=['GET']) 4def top_page(): 5 entries = DB_Training.scan() 6 entries = sorted(entries, key=lambda x: x.partition_key, reverse=True) 7 return render_template('entries/top_page.html', registration_data=entries) 8

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答1

0

ベストアンサー

質問文記載のコードでは、起動時に
main 内で sub がインポートされ、
その sub 内で sub2 がインポートされ、
その sub2 内で DB クラスが読み込まれます。
そしてDB クラスが読み込まれる段階で自動的に

table_name = current_app.config['table_name']

が評価(「実行」)されますが、このタイミングでは current_app が空っぽのため、上記のエラーが発生しているのだと思われます。

アプリ全体における、sub2 にて定義している DB の使われ方が質問文に全く示されていないので何とも言えませんが
あくまで現状のコードの限りでは、下記のように必要なときに table_name を設定すればよいのではないのでしょうか。

sub2.py

python

1from flask import current_app 2 3class DB(): 4 table_name = '' 5 6 def initdb(): 7 DB.table_name = current_app.config['table_name']

sub.py

python

1from flask import Blueprint, current_app 2from sub2 import DB 3 4application_sub = Blueprint('sub', __name__) 5 6@application_sub.route('/') 7def top_page(): 8 DB.initdb() # 追加(たとえばここ以降でDBを使いたいというとき) 9 # 以下DBを使った処理。詳細は質問文に記載がないため不明。 10 # 略 11 return 'hello world'

追記内容について

下記のように、実行時に、必要な部分で内容を読みだし、設定するようにしてみてはいかがでしょうか。

DB

python

1from pynamodb.models import Model 2from pynamodb.attributes import UnicodeAttribute 3 4class DB(Model): 5 class Meta: 6 pass 7 8 def init_db(): 9 DB.Meta.table_name = application.config.get('TABLE_NAME') 10 DB.Meta.region = application.config.get('AWS_REGION') 11 DB.Meta.aws_access_key_id = application.config.get('AWS_ACCESS_KEY_ID') 12 DB.Meta.aws_secret_access_key = application.config.get('AWS_SECRET_ACCESS_KEY') 13 14 partition_key = UnicodeAttribute(hash_key=True, null=False)

View

python

1from sub import DB 2 3@application.route('/', methods=['GET']) 4def top_page(): 5 DB.init_db() 6 entries = DB_Training.scan() 7 entries = sorted(entries, key=lambda x: x.partition_key, reverse=True) 8 return render_template('entries/top_page.html', registration_data=entries)

(試せていないので、上記で正常に動くかどうかはわかりません)

投稿2022/11/27 05:10

編集2022/11/28 11:56
qnoir

総合スコア7894

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

MagMag

2022/11/28 02:52

qnoir様 回答ありがとうございます!実際のDB構造を入れる質問が複雑になるかな、と思って省略しましたが、アドバイスを受けてinit_dbメソッドを実装しようとしまいたが、PynamoDBの使い方としてclassをネストしているせいもあって、どのように実装したらいいかわかりませんでした。 実際のDBを追加して編集したので、可能だったらこのDBに対してどうinit_dbを実装したらいいか、ヒントをいただけないでしょうか?
MagMag

2022/11/28 13:42 編集

ありがとうございます。 sub2.pyでapplicationをimportするわけにはいかないと思い、applicationをcurrent_appに変えて実行すると"RuntimeError: Working outside of application context."が出ました。 また、init_db()をinit_db(self)にすると"TypeError: init_db() missing 1 required positional argument: 'self' "とエラーが出ます(selfを入れるとなぜselfがないって怒られるのか謎です)。classを重ねてこうなっているとは思いつつ、対応方法がわからないので、分割するのは諦めようかなと思います。 お付き合いいただき、ありがとうございます。

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Flask

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

Python 3.x

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