誰もがつまづくDjangoをHerokuにデプロイするときあるある

# はじめに

今回は「ツナキチ」というニューラルネットワークによる画像認識を用いて人間の顔が一体何％　ネコっぽいのかを調べられるWebサイトを作りました。
時間がなくてsafariではデザインが崩れてしまってます。いずれ直します！)
明示的にHerokuでデプロイしていることを示したいので、リンクを貼らさせてもらいます。
https://tunakichi.herokuapp.com/



使ったバージョンは

- python : v3.6.1
- django : v1.11.7

です。

コメント、いいね大歓迎です。誤字や間違いは指摘していただけると助かります。

# 前提
ここでは**すでにアプリは完成していて、いまからデプロイするぞ！**という方を前提にしています。
そしてデプロイをする上で、困ったことを紹介していきます。

# デプロイ
## pushする

まず、herokuのアプリケーションをherokuに登録しなければなりません。

```
heroku create <アプリ名>
```

で登録をすることができます。
一応、うまく繋がっているか確認してください。（これはgitとも接続されているか確認できるので初心者の人は使ってください。)

```
git remote -v
```

そして以下のように出ればおっけいです。

```
hogehoge:~/tunakichi[master]>> git remote -v
heroku	https://git.heroku.com/<リポジトリ名>.git (fetch)
heroku	https://git.heroku.com/<リポジトリ名>.git (push)
origin	git@github.com:KeisukeYamashita/<リポジトリ名>.git (fetch)
origin	git@github.com:KeisukeYamashita/<リポジトリ名>.git (push)
```

そしたら次にClearDBを作っていきます。簡単にいうとheroku上のDBです。

```
heroku addons:add cleardb:ignite
```

そしてherokuの環境変数を変更してください。

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

ここでアプリ側の設定を変えなければなりません。`wgsi.py`に以下に変更してください。

```
import os

from dj_static import Cling
from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<アプリ名>.settings")

application = Cling(get_wsgi_application())
````

これで設定ができたので、pushすればデプロイできます。

```
git add .
git commit -m "hogehoge"
git push origin master
git push heroku master
```

## 確認

`git push heroku master`のときにURLがすでに表示されるのですが、開くには以下のコマンドが便利です。


```
heroku open
```

またマイグレーションが必要な方は以下のコマンドでしてください。

```
heroku run python manege.py migrate
```

さらにシードデータがあるときは`loaddata`で入れることができます。
Djangoでは`JSON`によるシードデータを入れる方法と、`.YAML`によるシードデータの入れ方があります。

```
heroku run python manegy.py loaddata <シードデータファイル(JSONorYAML)>
```

これで再起動すると正しく動くはずです。

```
heroku restart
```

# トラブルシューティング
## [ケース1] herokuへのpushがrejectされる`No default Language`
これはDjangoをデプロイしようとしている人の多くが直面する問題です。
### 原因
ディフォルトでなんの言語を使うのかを指定していないことが問題です。
herokuでは次のような言語がサポートされていて、簡単にいうと**どの言語を使いますか**という設定をしないといけない。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/153320/71972271-768b-e7ca-e49e-dc2400ff3db2.png)

今回はPythonを使います。

### 解決策

まず、pythonのバージョンを`runtime.txt`に書き込みます。

```
echo $(python -V) > runtime.txt
```

次にローカルで使っているパッケージをherokuでも使いたいのでrequirement.txtに記載します。

```
pip freeze > requirement.txt
```

そして`push`すればリジェクトされないはずです。

## [ケース2]無料枠の落とし穴。「たまに見ると落ちているんですけど、、、」
### 原因
herokuの無料枠では、30分間アクセスがなれけばスリープモードに入ってしまい、再起動が必要となります。

### 解決策
毎20分ごとぐらいにherokuに自分でアクセスしてもいいのですが、これを自動化しましょう。
**デプロイしたWebサーバー自体が自分にアクセスするように組めばいいのです。**

'`<アプリ名>/wgsi.py`に以下を追加してください。

```:wgsi.py

import os
import threading
import requests
import time


def awake():
    while True:
        try:
            print("Start Awaking")
            requests.get("http://hogefuga.herokuapp.com/")
            print("End")
        except:
            print("error")
        time.sleep(300)

t = threading.Thread(target=awake)
t.start()
```

これによって自分にアクセスするようになるので、サーバーがスリープになるようなことはなくなります。


## [ケース3]変な名前のモジュールがない。`No module　name _tkinker`
### 原因
これはグラフを書くのによく使われる`matplotlib`ライブラリに含まれるmoduleであり、これがherokuでインストールされていないことが原因です。

### 解決策
まず**サーバーにmatplotlib**を使うことはおかしいです。笑
(僕はローカルで使っていた数値計算アルゴリズムをそのまま.pyファイルとしてサーバーの計算部分に使おうとしたら勝手に混入していました）

なのでアプリ内の全`import <Matploblib>`を削除すれば解決できます。

## [ケース4]ケース３の一般系。`No module name hogehoge`
### 原因
とある`hogehoge`モジュールがないといっています。
これは抽象度が高いので、原因がいくつか考えられると思います。

### 原因1. そんなモジュールなんてない説
本当にそのモジュールがあるかを確認してください。
タイピングミスでmodule名が変わっていないですが？

### 原因2. herokuにインストールされていない説 ←　定説
ローカルで追加で開発をして、再度pushしたとします。
ローカル環境で新しくpipで導入したことをherokuは知りません。

なので`requirement.py`を更新することが必要です。

```
pip freeze > requirement.txt
```