Djangoで作ったWebアプリをherokuにデプロイする～venv環境にて～


# 背景

DjangoでWebアプリを作る際、herokuにデプロイするのはとても手軽で便利です。
しかし、本番用とローカル開発用の両立した設定はなかなかややこしいです。
毎回どうやったらいいか忘れて検索しているため備忘録として残しておきます。

# この記事を読んで得られる知見

+ venvでの環境構築
+ Djangoで作ったアプリをheroku向けにデプロイするための設定

# この記事で扱わないこと

+ Djangoでのアプリケーション作成方法
+ heroku関連以外のミドルウェア・ライブラリ

# 環境・使用ツール

+ VSCode
+ python-3.9.10
+ Django==4.0.2

## Pythonのvenv環境を構築する


```python:Macの場合
python3 -m venv test-python #仮想環境の作成

source test-python/bin/activate #アクティブ化

pip install --upgrade pip #pipをアップグレード
```

```python:Winddowsの場合
python -m venv test-python #仮想環境の作成

source test-python/Script/activate #アクティブ化

pip install --upgrade pip #pipをアップグレード
```


:::note warn
私のようにMacとWindowsを行き来する場合は、.gitignoreを作成して仮想環境（test-python）は管理外にしておいた方が良いです
:::

## djangoでプロジェクト、アプリケーションを作成する

```shell:
pip install django #Djangoをpipで入れる

django-admin startproject config #プロジェクトを作成

cd config #フォルダ移動

python manage.py startapp app #アプリケーションの作成

```

## ローカル開発用のセッティング

### 環境の分離

heroku用とローカル開発用でセッティングを使い分けます。
`setting.py`の末尾に下記を追加します。

```python:setting.py
SECRET_KEY = os.environ.get("SECRET_KEY") #SECRET_KEYは後述のファイルに記載して書き換え

DEBUG = False

try:
    from config.local_settings import *
except ImportError:
    pass

if not DEBUG:
    import django_heroku
    django_heroku.settings(locals())
```

ローカル開発用の設定を`local_settings.py`に書きます。

```python:local_settings.py
import os
SECRET_KEY = "" #setting.pyからこちらにコピー

ALLOWED_HOSTS = []
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

DEBUG = True
```

:::note warn
setting.pyは公開されてしまうので、SECRET_KEYはlocal_settings.pyに記載し、local_settings.pyは.gitignoreに追記してgit管理外にしておきましょう
:::


### データベースの設定

heroku上で動かすデータベースに関する設定をします。
`setting.py`に下記のコードを追加しましょう。


```python:setting.py
import dj_database_url
db_from_env = dj_database_url.config()
DATABASES['default'].update(db_from_env)
```


### 静的ファイル用の追記

```python:setting.py
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
```

:::note warn
staticfilesは.gitignoreに追記してgit管理外にしておきましょう
:::

## heroku用の環境設定

### 関連ライブラリのインストール

```shell
pip install dj-database-url #herokuではpostgreSQLでデータベースを管理
pip install django-heroku #herokuでdjangoを動かす
pip install gunicorn #heroku上でコマンドをwsgiを実行するために必要
pip install psycopg2 #PythonでpostgreSQLを動かすために必要
```

### Procfileの作成
herokuにデプロイした後に実行したいコマンドを書いておきます。
`config`フォルダ内のwsgi.pyを実行しています。
前2行でマイグレーション関係のコマンドを追加してますが、3行目だけあれば大丈夫です。

```text:Procfile
release: python manage.py makemigrations
release: python manage.py migrate
web: gunicorn config.wsgi --log-file 
```

### runtime.txtの作成
heroku上で動作するPythonのバージョンを指定します。
仮想環境上で`python --version`を実行して確認しておきましょう。

```text:runtime.txt
python-3.9.10
```

:::note warn
pが大文字、-が無いなどでエラーが起きやすいので要注意
:::

### requirements.txtの作成
使用するライブラリを指定しておく必要があります。
仮想環境上で`pip freeze > requirements.txt`とすれば作成できます。


### ホワイトリストへの追加
Djangoではホワイトリスト方式でホストが制限されています。
`config/settings.py`の`ALLOWED_HOSTS`に`*.herokuapp.com`を追加しておきます。
下記のようにherokuアプリ名まで記載しても問題ありません

```python:settings.py
ALLOWED_HOSTS = ["{Herokuアプリ名}.herokuapp.com"]
```

### .gitignoreの内容

最終的には下記を記載してます。

* `staticfiles` 
静的ファイルはstaticフォルダに入れて、staticfilesには余計なファイルを置かない
* `config/local_settings.py`
ローカル開発用のため除外
* `db.sqlite3`
ローカル開発で使用したデータベースは除外
* `test-python`
仮想環境も除外しておく

## Herokuにデプロイ

### Herokuに登録する
[こちら](https://signup.heroku.com/jp)からユーザー登録しておきましょう。

### Heroku CLIのインストール
[こちら](https://devcenter.heroku.com/ja/articles/heroku-cli)を参考にしてください。

### Herokuでアプリ作成

まずはログインします。

```shell
heroku login
```

画面遷移してログインしたらHerokuでアプリを作成します。

```shell
heroku create {アプリ名}
```

### SECRET_KEYを登録

`https://dashboard.heroku.com/apps/{アプリ名}/settings`にアクセスして`Config Vars`のところでSECRET_KEYを登録しましょう。

下記のように入力してADDすれば登録できます。

```text
KEY="SECRET_KEY" VALUE="{Djangoのsetting.pyに載っていたSECRET_KEYの値}"
```

あるいは、下記のようなコマンドでも登録できます。

```shell
heroku config:set 環境変数名{SECRET_KEY}=値{setting.pyに記載されたSECRET_KEYの値}
```

### pushする

コミットしてからpushします。
Procfileにマイグレーションの記述があればmigrateまでしてくれます。
`python manage.py createsuperuser`はheroku画面上からMore>Run consoleから叩くか`heroku run python manage.py createsuperuser`とすれば実行できます。
マイグレーションなども同様に可能です。

```shell
$ git add .
$ git commit -m "django app commit"
$ git push heroku master
```


## 最後に
DjangoでWebアプリを作ってデプロイできるのは便利ですが、設定時には色んなエラーと遭遇しました。

ローカル開発環境と両立しながらデプロイ設定を記述する際に、参考になれば幸いです。