[Windows]FlaskのwebアプリをHerokuにデプロイ

# はじめに

Flaskで作成したアプリのデプロイに詰まったので、記録として残しておきます。

# 環境

- Windows10 Home
- Flask
- SQLite3（ローカルでの実行）
- PostgreSQL（デプロイ）

# 注意

- <strong>HerokuはSQLite3に対応していません</strong>
- <strong>GunicornはUnix環境でしか動作しません</strong>

# Flaskアプリの作成

まず、Github上でリポジトリを作ります。そのうえで、任意のディレクトリにて

```
git clone <repository url>
```

をするとgitを使えるようになります。

### 仮想環境

virtualenvを使って仮想環境を作る場合は、

```
pip install virtualenv
virutakenv myflaskapp
cd myflaskapp
source bin/activate
```

これで環境内に入れるはずです。

### ファイル構成

今回のファイルでは、以下のような構成をとっています。

`main.py`はrunするだけで、`__init__.py`に諸々の初期設定を入れ、`models.py`にデータベースの設計を入れています。

`migrations`フォルダは後述するデータベースの設定をしたときに生成されるものです。このフォルダはデプロイ時に必要となりますので、`.gitignore`しないように気を付けてください。

```
├───main.py
├───requirements.txt
├───migrations
├───myproject
│   │   data.sqlite
│   │   models.py
│   │   __init__.py
│   │
│   ├───static
│   ├───templates
│          base.html
│          home.html
│          404.html
```

### `main.py` / `__init__.py`

`main.py`は以下のようになっています。

```python:main.py

from flask import render_template
import os

from myproject import app

@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template('home.html')

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)), debug=True)
```

特に重要なのは`app.run`の中で、`host`と`port`を必ず設定するようにしてください。(`debug=True`はオプション)

`__init__.py`は以下のようになっています。

```python:__init__.py

import os
from flask import Flask, redirect, url_for, flash, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__, static_folder='static', template_folder='templates')

# Often people will also separate these into a separate config.py file
app.config['SECRET_KEY'] = 'mysecretkey'
basedir = os.path.abspath(os.path.dirname(__file__))

# Heroku Postgresアドオンを追加した場合、環境変数DATABASE_URLに
# PostgreSQLデータベースの接続先URLがセットされるので、この値が
# セットされているとき(Heroku上で動作するとき)はそれを使い、
# セットされていないとき(ローカルでのデバッグなど)はローカルのSQLiteデータベースを使うようにする。

SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data.sqlite')

app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
Migrate(app,db)
```

コメントにあるように、ローカルではSQLiteを使い、Heroku上ではPostgresを使います。

`Heroku Postgres`アドオンについては後述します。

### データベースの初期化

一度初期化して、ローカルで動作することを確認します。

```
set FLASK=main.py
flask db init
flask db migrate -m "init db"
flask db upgrade

python main.py
```

これで、[http://127.0.0.1:5000/](http://127.0.0.1:5000/)にアクセスし、無事に表示されれば成功しています。

このときに生成された`migrations`フォルダは`gitignore`しないようにしてください。

# デプロイ

アプリが完成したとして、次にデプロイします。

Heroku上では、PostgreSQLを使用するので、必要なパッケージをインストールします。

```
pip install psycopg2
```

これだけです。

### 必要なファイルの準備

デプロイに必要なファイルは以下の通りです。

- Procfile
- requirements.txt
- runtime.txt 

ほとんどの記事では、`gunicorn`をサーバーに使っていると思うですが、これはUnix派生の環境でのみ動作します。よって、Windows環境でも動作するものを選択するのですが、今回はpythonでwebサーバーを構築するので、以下のようにします。

```:Procfile
web: python main.py
```

続いて、`requirements.txt`ですが、`psycopg2`をインストールしたことにより、必要なインストールはすでに終えているので、次にようにして書き出します。

```:requirements.txt
pip freeze > requirements.txt
```

`runtime.txt`はpythonのバージョン指定に使われます。例えば、`python-3.8.5`を使用している場合は、

```:runtime.txt
python-3.8.5
```

とします。

### Heroku CLIのインストールとアカウント作成

Heroku CLIをインストールします。

[https://devcenter.heroku.com/articles/heroku-cli#download-and-install](https://devcenter.heroku.com/articles/heroku-cli#download-and-install) 

ここにアクセスし、`Windows 64-bit installer`からインストールしてください。

インストールが完了したら、[https://signup.heroku.com/login](https://signup.heroku.com/login) でアカウント作成します。

### Herokuアプリ作成

アカウント作成を完了したら、アプリを作成します。

```
heroku login
heroku create <アプリ名> # 被らないアプリ名を登録
```
をやればできます。

### Heroku Postgres アドオンの追加

ログインしてアプリを作成したら、Heroku Postgresql アドオンを追加します。これをやらないと、`DATABASE_URL`を見失ってしまいます。

今回は、無料で使うので、`Hobby Dev`プランを選択します。

```
heroku addons:create heroku-postgresql:hobby-dev
```

これで、`DATABASE_URL`に登録されているはずです。

### プッシュ

次に、リモートリポジトリへプッシュします。

```
git add .                # 新たに作成したファイルがあるため
git commit -m "message"
git push heroku master 
```

ここで、`heroku open`をしても、おそらく`Application Error`が表示されます。なので、次を実行します。

### Application Error の回避

```
heroku config:set FLASK_APP=main
heroku run flask db upgrade
```

このときに、`migrations`が必要です。


これで、完了です。

```
heroku open
```
でアプリが表示されているはずです。

# 参考記事

- [【Python/Flask】作成したアプリをHerokuで公開する方法（Windows）](https://algorithm.joho.info/programming/python/flask-heroku/)
- [FlaskとPostgreSQLでウェブアプリを作ってHerokuで無料で運用する](https://qiita.com/croquette0212/items/9b4dc5377e7d6f292671#heroku%E3%81%ABdeploy%E3%81%99%E3%82%8B)
- [【完全版】Flaskで作ったAPIをHerokuにデプロイする手順（備忘録）](https://qiita.com/ahpjop/items/e333eaf304dcdd72d886)
- [HerokuにFlaskアプリをデプロイする](https://qiita.com/redpanda/items/a056daea48b545250ce7)
- [Flask + Herokuでアプリを動かす](https://qiita.com/svfreerider/items/50c68252c2f119583a28)


# おわりに

これでは動作しない、などの問題がありましたらご指摘の程よろしくお願いいたします。