Flaskでデータベースが作成されない時〜RuntimeErrorを読み解く〜

以前Flaskでアプリ制作をしてた時にデータベースファイルが作れないエラーが起きたので記録していきたいと思います。

Flaskでデータベースを作成する時はSQLAlchemyを使うのが便利。ちゃんとインポートしときましょう。

一応こちら👇は簡単なサンプルコード。ちなみに仮想環境は使用していません。

```python:app.py
from flask import Flask
from flask import render_template, redirect, request
from flask_sqlalchemy import SQLAlchemy



app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///lesson.db'
db = SQLAlchemy(app)

class Lesson_db(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)


@app.route('/')
def index():
    return 'test'

if __name__ == ('__main__'):
    app.run(debug=True)
```

これをrunすると
![スクリーンショット 2022-11-29 11.11.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2980135/10eac2c3-9916-3c70-c129-911b3543fa96.png)

なんかシュールな見た目ですが正常にアプリが起動しました。w

次にデータベースを起動させます。お試し用なんでnameカラムしか用意してません。

```python:app.py
class Lesson_db(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
```




ターミナルで一度flaskサーバーを切ってpython対話モードを開きます。
そのままpythonかpython３と入力しましょう

```terminal
$ python3
Python 3.9.12 (main, Apr  5 2022, 01:53:17) 
[Clang 12.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
```

そして一番下の矢印にapp.pyからデータベースのdbをインポートします。

```
>>> from app import db
```

続いてこちら👇の関数。これでデータベースファイルが作られる訳ですが私の場合・・


```
>>> db.create_all()
```

👇こんなん出ちゃいました。

```
raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.
```

公式ドキュメントで調べてみたところ、

https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/appcontext.html

>もしcurrent_appまたはcurrent_appを使うものへのアクセスを試すとき、application contextの外側の場合（application contextがスタックへpushされた状態でない場合）、以下のようなエラーメッセージを得るでしょう:
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that
needed to interface with the current application object in some way.
To solve this, set up an application context with app.app_context().

まさに自分のケースとドンピシャ。
でもねードキュメントさん、外側とかpushされた状態じゃないとか何言ってんのかわからんのよw

これは勝手な自分の解釈だけど、今回はターミナルでpython３コマンドを使ってますが例えば仮想環境で他のコマンド（anacondaとかdockerなど）とか、あるいは３じゃないただのpythonコマンドを使ってたら違ったのかな、と想像してみたり。
要はWorking outsideだからテメェのpython３じゃアクセス出来ねぇってことなんですかね。

そんでさらに読み進めると

>もし自分のアプリケーションを設定中に、例えばFlask拡張を初期化しているときなどに、このエラーを見た場合は、appへの直接アクセスが可能なので（訳注: app設定中であれば、appインスタンスに直接アクセスして設定の初期化や値の定義などができる状況なはずなので）contextを手動でpushすることが可能です。withブロックの中でapp_context()を使用すると、ブロックの内側で実行しているものは全てcurrent_appへアクセスできるようになります。

お、なんかよくわからんけどwithとapp_contextを使えと。
早速対話モードを再開して、

```
$ python3
Python 3.9.12 (main, Apr  5 2022, 01:53:17) 
[Clang 12.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from app import app
>>> from app import db
>>> with app.app_context():
...     db.create_all()
... 
>>> exit()
```

with文でapp_context()を使ってみました。
（ちなみに色々調べた結果一番最初にfrom app import appとするのがベターだそうです）

そしてVS CODEの左側を見ると・・

![スクリーンショット 2022-11-29 11.55.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2980135/df8f8217-eb90-d968-a3a9-aed83d32b93c.png)

出来たー！！
ちゃんとapp.configで名付けたlesson.dbが作成されてます。

感無量。これで自由自在にSQLAlchemyを操ります。



次回はデータベースの基本、CRUD操作について解説したいと思います。