Django Girlsチュートリアルで Heroku へデプロイするときに躓いたこと -スタックに注意

Django Girls Tutorial: Extensions内の"Herokuにデプロイしよう"の項にて、記載通りに行ってもうまくいかず四苦八苦したので、ケースとして残しておきたいと思います。

[Herokuにデプロイしよう（PythonAnywhereだけでなく）](
https://tutorial-extensions.djangogirls.org/ja/heroku "Herokuにデプロイしよう（PythonAnywhereだけでなく）")

##Herokuへデプロイ時にエラー

チュートリアル通りに進めHerokuへデプロイすると以下のようにエラー。

```
Requested runtime (﻿python-3.6.4) is not available for this stack (heroku-20).
```
エラーメッセージ通りに受け取るとpythonのバージョンが対応していない？

###サポートするpythonのバージョンをインストールする 
[Herokuのサポートページ](https://devcenter.heroku.com/ja/articles/python-support#specifying-a-python-version)を確認すると以下のようにあるので、3.7.4をインストールしてみる。

>​python-3.7.4​ (すべてのランタイムスタック)
>python-3.6.9​ (すべてのランタイムスタック)
>​python-2.7.16​ (すべてのランタイムスタック)

runtime.txtの記述も変更することを忘れずに。

```runtime.txt
python-3.7.4
```

先頭文字を大文字にしたり、ハイフンを忘れると認識されないので注意。

結果はNG

```
Requested runtime (﻿python-3.7.4) is not available for this stack (heroku-20).
```

バージョンは変わったが、何故かサポートされないと変わらず。
サポートページではすべてのランタイムスタックをサポートと書かれていたのに...

###Whitenoiseを疑う
Herokuを利用する際にWhitenoiseというMiddlewareを使用する。
ただ、正常に利用するためには一部記述を書き換えなければいけない様なので修正する。

[Using WhiteNoise with Django](http://whitenoise.evans.io/en/stable/django.html#)

`STATIC_ROOT`に`'staticfiles'`を追加。

```settings.py
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
```


`MIDDLEWARE`に`'whitenoise.middleware.WhiteNoiseMiddleware',`を追加。
`django.middleware.security.SecurityMiddleware'`の後、かつ他のMIDDLEWAREより前に記述した方がよいそうです。

なので↓こんな感じ。

```settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    # ...
]
```

結果はやはりNG

###Herokuのスタックの問題？

今回作成したAppはスタック20だった。

サポートページではスタックによってサポートされるバージョンが違うことがありそう。

3.7.4はすべてのスタックをサポートしていると記載はされているが、
**スタック20が3.7.4をサポートしているかどうか**の記述を見つけることができなかった。

と思ったら、日本語ページでは3.7.4はすべてのスタックでサポートと記載されているのに、英語ページでは書いてあることが違うじゃないか！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230966/92e8275d-f61f-c352-da71-418b1ac39360.png)

[Heroku Python Support | Heroku Dev Center](https://devcenter.heroku.com/articles/python-support)

どうやらスタック20は3.7.4には対応していない様子。
ということでスタック18ならサポートしているかもということでスタック18でAppを作成してみることに。

[最新スタックへのアップグレード | Heroku Dev Center](https://devcenter.heroku.com/ja/articles/upgrading-to-the-latest-stack)

`heroku create`の後に`--remote heroku-18 --stack heroku-18`とスタック番号を指定することで、任意のスタックでAppを作成できる模様。

```
$ cd <yourcodedirectory>
$ heroku create --remote heroku-18 --stack heroku-18 <your app name with heroku-18 appended>
```

結果、スタック18のAppにデプロイしたところ成功！！
ただし、別のエラーが発生。
アプリケーションをアップデートするか、もしくはdisableにしろとのこと。

```
remote:  !     Error while running '$ python manage.py collectstatic --noinput'.
remote:        See traceback above for details.
remote: 
remote:        You may need to update application code to resolve this error.
remote:        Or, you can disable collectstatic for this application:
remote: 
remote:           $ heroku config:set DISABLE_COLLECTSTATIC=1
```

###collectstaticの設定を見直し

エラーの内容は静的assetの設定のようだが、前述のWhitenoiseの設定と、collectstaticの機能が勝手にactiveになるそう。
これを最適化するかdisableにすることが必要のようで、一旦はよくわからないのでdisableにすることとした。必要なら後で調べよう。

[Django and Static Assets | Heroku Dev Center](https://devcenter.heroku.com/articles/django-assets)

```
$ heroku config:set DISABLE_COLLECTSTATIC=1
```

###migrateしたらmoduleが見つからない！？

改めてデプロイするために事前に`collectstatic`コマンドと`migrate`コマンドを実行。

```
$ python manage.py collectstatic
$ python manage.py migrate
```

すると、今度はmoduleが見つからないエラー

```
ModuleNotFoundError: No module named 'dj_database_url'
```

これは仮想環境で実行していたにもかかわらず、`pip`でインストールしていたからと判明。
改めて`pipenv`でインストール。他にもいくつか`pip`でインストールされていたものがあったので、それらもインストールしなおし。
これで、モジュール見つからないエラーも解消。

```
$ pipenv install dj-database-url
```

この後に再度デプロイを実行し、ようやく成功！！

お疲れさまでした。


###Webにアクセスするもアプリケーションエラー

ようやくデプロイ成功したのでWebから早速アクセスしてみたけどアプリケーションエラー。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230966/f7e8c274-d571-d384-ad66-2757cee20091.png)

`heroku logs --tail`でログを確認したが原因はよくわからず。

```
at=error code=H10 desc="App crashed" method=GET path="/"
```

これについては調査中...

(1/30追記：)

エラー内容は以下。

`gunicorn`が見つからない的なエラーを吐いているので、これも仮想環境にモジュールがインストールされていないことが原因？

```
2021-01-29T15:34:05.223661+00:00 heroku[web.1]: State changed from crashed to starting
2021-01-29T15:34:10.461232+00:00 heroku[web.1]: Starting process with command `gunicorn mysite.wsgi --log-file -`
2021-01-29T15:34:13.054050+00:00 app[web.1]: bash: gunicorn: command not found
2021-01-29T15:34:13.103594+00:00 heroku[web.1]: Process exited with status 127
2021-01-29T15:34:13.145907+00:00 heroku[web.1]: State changed from starting to crashed
```

なので、改めて仮想環境にインストール。
`whitenoise`も同様のエラーだったため、それもまとめて。

```
$ pipenv install gunicorn
$ pipenv install whitenoise      
```

これで、もう一度Herokuへ`push`し、`migration`を実行したところ、無事改善。
エラーなくWebページが表示された！

##まとめ

根本原因は**Herokuの最新のスタック20では、python3.7.4に対応していない**ことでした。

このスタック20は2020/4にリリース？されているようで比較的新しいみたいです。
そのためかスタックによるサポートの違いについて言及されている記事がなかったので同じように困っている方に届けばいいいなと思い記事にしてみました。

もし、間違っていることなどあればご指摘いただけると幸いです。