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

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

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

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

Python 3.x

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

Q&A

解決済

1回答

1808閲覧

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

MagMag

総合スコア80

Flask

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

Python 3.x

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

0グッド

1クリップ

投稿2022/11/27 00:42

編集2022/11/28 22:42

前提

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

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

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

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

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

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

guest

回答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
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

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を重ねてこうなっているとは思いつつ、対応方法がわからないので、分割するのは諦めようかなと思います。 お付き合いいただき、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問