『ゼロからFlaskがよくわかる本』読書メモ

# 概要

以下の書籍を読み進めた際の読書メモです。
所要時間は約15時間。(うち環境構築周りの作業や調査が3時間程度)
触れ込み通り、非常に軽量でサクサク開発でき、拡張も容易なフレームワークという印象でした。

# 書籍概要

- 書籍名：ゼロからFlaskがよくわかる本
- 著者　：本田崇智
- 発刊日：不明（2018年7月頃？）
- 頁数　：214ページ
- 備考　：Kindle版のみ

# 環境構築

## Python環境構築

- brewでインストールしていたPythonのアンインストール
    - ```$ brew uninstall python```
    - ```$ brew uninstall python3```

- 公式インストーラでインストールしていたPythonのアンインストール
    - [Macにインストールした公式Pythonをアンインストールする方法](https://code-graffiti.com/how-to-uninstall-official-python3-on-mac/#toc1)

- pyenvのセットアップ
    - [pyenvを使ってMacにPythonの環境を構築する - Qiita](https://qiita.com/1000ch/items/93841f76ea52551b6a97)

- pyenvによるPythonのインストール・バージョン指定・動作確認
    - ```$ pyenv install -l```
    - ```$ pyenv install 3.8.2```
    - ```$ pyenv rehash```
    - ```$ pyenv global 3.8.2```
    - ```$ pyenv versions```
    - ```$ which python```
    - ```$ python -V```
    - ```$ python2 -V```
    - ```$ python3 -V```

- pipのインストール・動作確認
    - ```$ pip install --upgrade pip```
    - ```$ pip -V```
    - ```$ pip3 -V```

- Pipenvのセットアップ（プロジェクトごとに専用環境を構築しパッケージを管理できる）
    - ```$ pip install pipenv```
    - ```$ pipenv --version```

- 今後は```$ pipenv shell```で仮想環境に入ってから各種パッケージのインストールやコマンドの実行を行う
    - 仮想環境にインストールしたパッケージは```$ pipenv graph```で確認可能

## 参考情報：MacのデフォルトのPythonについて

- macOSにはデフォルトでPython2.7が入っている
    - 実体は```/System/Library/Frameworks/Python.framework```以下（システムで使われているため消したりはできない）

- さらに、macOS CatalinaにはPython3も入っている（2020年5月時点のバージョンは3.7.3）
    - 実体は```/usr/bin/python3```（同じく消せない）

- /usr/bin/を見ると```python```と```python2```系のコマンドは全て上述したPython2.7へシンボリックリンクが張られている
    - ```python3```コマンドはシンボリックリンクではなく直接置かれているバイナリを呼んでいるだけ

```
$ ls -la /usr/bin/python*
lrwxr-xr-x  1 root  wheel     75 10  8  2019 /usr/bin/python -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
lrwxr-xr-x  1 root  wheel     82 10  8  2019 /usr/bin/python-config -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7-config
lrwxr-xr-x  1 root  wheel     75 10  8  2019 /usr/bin/python2 -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
lrwxr-xr-x  1 root  wheel     75 10  8  2019 /usr/bin/python2.7 -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
lrwxr-xr-x  1 root  wheel     82 10  8  2019 /usr/bin/python2.7-config -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7-config
lrwxr-xr-x  1 root  wheel     76 10  8  2019 /usr/bin/pythonw -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/pythonw2.7
lrwxr-xr-x  1 root  wheel     76 10  8  2019 /usr/bin/pythonw2.7 -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/pythonw2.7
-rwxr-xr-x  1 root  wheel  31488  3 18 00:42 /usr/bin/python3
```

- ちなみに```pip```については```pip3```しか入っていない模様

```
$ ls -la /usr/bin/pip*
-rwxr-xr-x  1 root  wheel  31488  3 18 00:42 /usr/bin/pip3
```

- ```~/Library/Python```にもPython関連のファイルがあるが、ここには```pip```でインストールしたライブラリが入っている

# 読書ノート

## Flaskの特徴・設計思想

- Werkzeug・Jinja2に基づくPython用のマイクロフレームワークで、非常に軽量
    - Werkzeug（ヴェルクツォイク）：シンプルなWSGIユーティリティライブラリ
        - WSGI（ウィスキー）：PythonにおいてWebサーバとWebアプリを接続するためのI/Fライブラリ
    - Jinja2：PythonのWeb開発で良く使われるテンプレートエンジンライブラリ

- ユーザのリクエストを受けて結果を返すというコア機能だけ実装されている
    - デフォルトでは上記2つのライブラリしか持たないのでDBや認証周りなど余計なものが入っていない

- 拡張機能を組み合わせることでスケーラブルなアプリ作成も可能（カスタマイズ性が高い）

- DjangoだとRDBがセットになるが、FlaskだとNoSQLなども利用できる

- マイクロサービスとの親和性が高い

- Flaskを使っているサービスの例：Netflix、Lyft、Linkedin、Mailgun、Pinterest

## Djangoの特徴・設計思想

- Web開発に必要なほとんどの機能が入っているフルスタックフレームワーク

- 型に従ったクリーンな開発が可能

- Djangoを使っているサービスの例：Instagram、Bitbucket、Udemy、Dropbox、Spotify、Youtube

## Flask全般

- FlaskはMTVフレームワーク（Model・Template・View）
    - 主な処理の流れ
        - ユーザが特定URLにアクセス（リクエスト）
        - アクセスされたURLを読み取り、URLに紐付いた処理を実行する（View）
        - 上記の処理中で、Modelオブジェクトを通してDBにアクセスする（Model）
        - 処理の最後に、ユーザに表示するHTM等のテンプレートを返す（Template）
        - ブラウザに返されたHTMLが表示される

## ビュー・テンプレート

- ビューでテンプレートを表示（render_template）する際、パスに「/templates」を含める必要はない
    - FlaskではHTMLファイルはtemplatesフォルダ以下に作成するのがルール

- ルーティング設定にて```methods```を指定した場合、そのURLに対して許可するHTTPメソッドを制限できる
    - 何も指定しない場合はGETのみ許可される

- FlaskでHTMLをレンダリングする際はJinja2を使っているため、HTML内での条件分岐やビューから受け取った変数の使用等が可能
    - 例：```{% if not session.logged_in %}```

- ユーザにメッセージを表示する際は```flash```を使う
    - ビュー：```flash('メッセージ')```
    - テンプレート：```get_flashed_messages()```

- ```url_for ```を使うと、リンク名とメソッドを自動的に紐付けてくれるので、リンク先が変わってもコード修正が不要になる
    - 当然ビュー側だけでなくテンプレート側のコードにも記述可能

- ```return render_template('entries.html', entries=entries)```のようにすると、テンプレートに引数を渡せる

- ```url_for('メソッド名', id=entry.id)```のようにすると、ビューのメソッドに引数を渡せる

- ```app.route('/entries/<id>') ```のようにすると、```url_for```で渡された引数を受け取れる
    - 受け取る引数の型を制限したい場合は```<int:id>```のようにする（それ以外の型の場合はエラーになる）

- redirectとrender_templateの使い分け
    - [Python - redirectと書かれている部分はrenderではだめなのか？｜teratail](https://teratail.com/questions/90799)

## モデル

- ModelはPythonにおけるclassとして定義する

- ```def __init__()```でModelが作成されたときの標準動作を定義する

- ```def __repr__(self)```でModelが参照されたときのコンソールの出力形式を記述する（なくても良い）

- Modelを定義したらDBに反映させる必要がある（主に以下の2通り）
    - Modelの定義をコンソールで実行して反映する方法
    - スクリプトを作成して反映する方法

- ModelごとにViewを用意し1対1で紐付けてファイルを作成すると良い

## セッション

- Flaskでは```session```という変数でセッション情報を扱える
    - 設定：```session['セッション名'] = True```
    - 確認：```if not session.get('セッション名'): (処理)```
    - 破棄：```session.pop('セッション名', None)```
        - 第2引数：既に破棄済みだった場合に返す値（特にない場合は```None```を指定しておく）
    - 暗号化：アプリ本体に```SECRET_KEY = '秘密鍵'```と設定すると自動的にセッション情報を暗号化してくれる

## DB

- Flaskで簡単にDBを設定し使いたい場合は```Flask-SQLAlchemy```ライブラリを使うと良い

- FlaskはMTVフレームワークなのでModelを定義すればORMを使って簡単にDB操作が可能

## デコレータ

- 繰り返し登場するView内の処理はデコレータを使うと良い（ライブラリで拡張する）
    - 例：ログインしているかどうかのセッション判定を共通化する

## Blueprint

- 大きくなってきたアプリの機能を分割する場合はBlueprintを使うと良い（ライブラリで拡張する）
    - アプリ中に複数の機能がある時、機能を小さなアプリとして独立させて構成できる
        - 例えば、ブログであれば記事関連の機能とコメント関連の機能をそれぞれ独立したアプリとして構成できる
            - アプリごとにView・Template・staticファイルをひとまとめとして独立させる（divisionalな構造化）
    - Templateやstaticファイルは各アプリで共通で、Viewだけ分けることも可能（functionalな構造化）
    - Blueprintを使ってアプリケーションを登録する際はURLにprefixを付与することも可能

## エラーハンドリング

- ```@app.errorhandler(エラー時のステータスコード)```でエラーのステータスコードごとに処理を定義できる
    - Blueprintを使う場合は```@(アプリ名).app_errorhandler(エラー時のステータスコード)```とする

## Flaskコマンドライン

- flaskコマンドラインも使える
    - 起動用のpyファイルを使用せずにアプリが起動できるようになる
    - flaskコマンドを使用する前提のライブラリ（Flask-Migrateなど）が使えるようになる
    - 環境変数の設定が必要
        - ```$ export FLASK_APP=(__init__.pyのあるディレクトリのパス)```：永続化する場合は適宜シェルの設定ファイルに追記する
        - ```$ export FLASK_ENV=development```：デバッグモードで起動する場合（未設定の場合は本番モード）

## アプリケーションファクトリ

- アプリケーションファクトリを使うと、グローバルではなく関数内でアプリを作成できる
    - これを使って作成したアプリは外部から直接参照できなくなるので、```current_app```メソッドを利用して呼び出す

## テスト

- Pythonのテストライブラリにも色々ある（今回はPython標準のunittestを使う）
    - テスト用のDB設定はアプリケーションの本体ファイルに記述して、テスト用のconfigを読み込めるようにする
    - ```def setup(self)```：テスト実行時に最初に実行されるメソッド
    - ```def tearDown(self)```：テスト終了直前に実行されるメソッド
    - ```def test_...()```：テストメソッド本体

- テストのカバレッジは```coverage```ライブラリで計測可能
    - ```$ pipenv install coverage```
    - ```.coveragerc```を作って以下の記述をしてテスト対象のフォルダを指定する
        - ```[run] source = ./(パス)```
    - ```$ coverage run -m unittest```
    - ```$ coverage report -m```：カバレッジの計測
    - ```$ coverage html```：カバレッジレポートの作成

## その他

- ```static ```ディレクトリ以下は自動的にCSSやJS等の静的ファイルを置く場所として認識される
    - 使用例：```<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">```

- jQueryのCDNから```jquery-3.2.1.slim.min.js```をインポートする記述があるが、現時点では3.2.1を3.5.1に書き換える必要あり