FlaskにDashを組み込む



# 全体の流れ
すでに何らかのFlaskアプリが構成されている前提としている。

1. dashapp.pyをルートに作成(異なる場所に作るなら、4.のインポートを変更する)
2. dashapp.pyから、Flaskインスタンスをimport(`from app import app`)
3. dashapp.pyにて、Dashインスタンスを作る際に、serverとしてインポートしたFlaskインスタンスを指定(`dashapp = dash.Dash(name='app1', server=app, url_base_pathname='/app1/')`)
4. ルーティングに追加する

# 想定している環境
## バージョン
Windows10上で実行
Python 3.7
Flask: 1.0.3
Dash: 1.0

## ディレクトリ構造

testapp.py <- flask runで実行されるファイル
dashapp.py
app/
    ├    \_\_init\_\_.py
    ├    routes.py

# 書き換えのポイント

## dashapp.pyの作成
Dashのチュートリアルなどを参考に作成する。とりあえず適当なグラフを用意。
ポイントは以下の2つ

- dashapp.pyから、Flaskインスタンスをimport(`from app import app`)
- dashapp.pyにて、Dashインスタンスを作る際に、serverとしてインポートしたFlaskインスタンスを指定(`dashapp = dash.Dash(name='app1', server=app, url_base_pathname='/app1/')`)

```py:dashapp.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import dash
import dash_core_components as dcc
import dash_html_components as html

from app import app

dashapp = dash.Dash(name='app1', server=app, url_base_pathname='/app1/')

dashapp.layout = html.Div(
   children =[
    html.H1('Hello Dash',),
    dcc.Graph(
        id="first-graph",
        figure={'data': [{'x': [1, 2],
                          'y': [50, 90],
                          'type': 'bar',
                          'name': 'A'},
                         {'x':[1,2],
                          'y':[70, 20],
                          'type': 'bar',
                          'name': 'B'}
                         ],
                'layout': {'title': 'Dash Test'}
                }
    )
   ]
)
```

## Flask側への組み込み

\_\_init\_\_.py. testapp.pyは特にいじらない。
※testapp.pyはflask runで起動されるファイル(`export FLASK_APP=testapp.py`で指定するもの)

```py:app/__init__.py
from flask import Flask

app = Flask(__name__)
app.secret_key = 'secret'

from app import routes, models
# この例ではmodelsは使っていない
```

```py:testapp.py
from app import app
```

ルーティング設定(routes.py)で、パスを設定する。
dashapp内のurl_base_pathnameで指定したパスにもアクセスはできるが、Flask側で管理したいならこれが必要)

```app/routes.py
from dashapp import dashapp

@app.route("/dash")
def MyDashApp():
    return dashapp.index()
```

# 課題
jinjaとの組み込みも可能だと思うが、まだできていない。

# 問題点(2019/7/7追記)
この方法でDashをFlaskに取り込んだ場合、dashapp内でデータベースの参照などを行っていると、データベースにカラム追加などをした際の`flask db migrate`が失敗する。
dashappをimportしている部分でエラーになるのだが、なぜだかはよくわからない。暫定的にはmigrateする際にimport文をコメントアウトしてしまえば大丈夫。

```shell-session
(venv) C:\Users\ikedak2\PycharmProjects\TimeRecorder_2019>flask db migrate
Traceback (most recent call last):
  File "c:\users\ikedak2\pycharmprojects\timerecorder_2019\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1244, in _execute_context
    cursor, statement, parameters, context
  File "c:\users\ikedak2\pycharmprojects\timerecorder_2019\venv\lib\site-packages\sqlalchemy\engine\default.py", line 550, in do_execute
    cursor.execute(statement, parameters)
sqlite3.OperationalError: no such column: project.projectcomsumedhours

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
(中略)
File "C:\Users\ikedak2\PycharmProjects\TimeRecorder_2019\app\routes.py", line 6, in <module>
    from dashapp import dashapp
  File "C:\Users\ikedak2\PycharmProjects\TimeRecorder_2019\dashapp.py", line 79, in <module>
    project_list = [project for project in Project.query.filter_by(projectstatus=True)]
```


# 参考
https://medium.com/@olegkomarov_77860/how-to-embed-a-dash-app-into-an-existing-flask-app-ea05d7a2210b