Flaskのフォルダ構成をまとめた

ずっとDjangoを使って、ウェブシステムを開発する人間。
隙間時間でシンプルなアプリでも作りたいなと思い、最近Flaskの勉強を始めている。
一つのファイルに、色々な設定を詰め込み過ぎるのはやっぱりよくないので、MVCに基づいて、ディレクトリ構成をまとめた。

```
flask_app
├ common
│ ├ libs
│ └ models  --- モデル
│ 　 ├ user.py
│ 　 └ ・・・
├ config　---　設定フォルダ
│ ├ base_setting.py　--- 各環境共通設定
│ ├ local_setting.py　--- ローカル開発環境用設定 
│ └ production_setting.py --- 本番環境用設定
├ controllers --- コントローラ
│ ├ index.py
│ └ ・・・
├ interceptors 
│ ├ auth.py --- 認証系処理
│ └ error_handler.py　--- エラー処理
├ static　--- 静的ファイル置き場所
├ templates　--- テンプレート
│ ├ common
│ │ └ layout.html
│ └ index.html
├ application.py　--- 複数のファイルが利用するものを定義（Flaskインスタンス、DB、環境変数など）
├ manager.py --- アプリ実行用スクリプト（アプリの入り口）
├ requirements.py --- ライブラリ一覧
└ www.py --- ルーティング
```
## 実行の流れ

* application.pyで、applicationとdbの初期化と設定を読みこむ  
(Djangoみたいに、コマンド(```python manager.py runserver```)でアプリ起動したいから、flask_script の Managerを利用する）
* Managerを噛ませたapplicationをwww.pyで読んでルーティング
* dbをmodelsで読みこんでモデル定義
* ルーディングしたapplicationをmanager.pyで実行 

## ファイル役割の説明
順に追って説明していく。
``` app.config.from_pyfile("config/base_setting.py") ```で共通設定をまず読みこむ。環境によって（開発・本番）変わる設定は、事前に設定した環境変数ops_configの違う値により、違う設定ファイルを読み込むようにした。

```flask:flask_app/application.py
from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)

manager = Manager(app)
app.config.from_pyfile("config/base_setting.py")

# linux export ops_config=local|production
# windows set ops_config=local|production
if "ops_config" in os.environ:
    app.config.from_pyfile("config/%s_setting.py" % (os.environ['ops_config']))

db = SQLAlchemy(app)

```
controllersの中身は機能単位で分割し、www.pyでblueprintを使って統合する。

```flask:flask_app/www.py
from interceptors.errorHandler import *
from interceptors.Auth import *
from application import app
from controllers.index import index_page

from flask_debugtoolbar import DebugToolbarExtension
toolbar = DebugToolbarExtension(app)


app.register_blueprint(index_page, url_prefix="/")

```
modelsの中にモデルを定義。ここではuser.pyにテスト用のモデルを定義した。

```flask:flask_app/common/models/user.py
from application import db


class User(db.Model):
    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(20), nullable=False)

```
controllersの中に実際の処理を定義。

```flask:flask_app/controllers/index.py
from flask import Blueprint, render_template
from common.models.user import User

index_page = Blueprint("index_page", __name__)


@index_page.route("/")
def index():
    name = "hello"
    context = {"name": name}
    context["user"] = {"nickname": "xxxx",
                       "id": "xxxxx", "home_page": "http://www.xxx"}
    context["num_list"] = [1, 2, 3, 4, 5]

    result = User.query.all()
    context['result'] = result

    return render_template("index.html", **context)

```
Managerのadd_commendメソッドで、コマンドrunserverとcreate_allを登録する。

```flask:flask_app/manager.py
 from application import app, db, manager
from flask_script import Server, Command
from www import *

# web server
manager.add_command("runserver", Server(host = "0.0.0.0", use_debugger=True, use_reloader=True))

# create tables
@Command
def create_all():
    from common.models.user import User  
    db.create_all()

manager.add_command("create_all", create_all)

def main():
    manager.run()
    
if __name__ == "__main__":
    # app.run( host = "0.0.0.0" )
    
    try:
        import sys
        sys.exit( main() )
    except Exception as e:
        import traceback
        traceback.print_exc()

```

## 実行
* ```pip install -r requirements.py ```で必要なモジュールをインストール。
* ```flask_app/local_setting.py ```で自分の環境に合わせて、dbのuser、password、host, portを設定。
* 自分の環境に名前がflaskのDBを作成。
* プロジェクトフォルダ(flask_app)の下で```python manager.py create_all```を叩く。
名前がuserのマスターが生成される。
* ```python manager.py runserver ```を叩き、
```http://localhost:5000```にアクセスして、次の画面出たら成功！
![flask_app_image.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545184/b64db0c9-64cf-0b1b-e7a8-9935f14b5008.jpeg)


## ソース
ソースをgitHubにアップしたので、時間あったら[ダウンロード](https://github.com/shixujapan/flask_app)して遊んでみてください。
## 次にやること

* Flaskを使い簡単なCRUDアプリを作成
* Vue.jsとの連携を考える