DjangoプロジェクトをHerokuにデプロイ

Djangoでプロジェクトをつくってデプロイで失敗し、何時間も時間を無駄にしてしまった方は多いと思います。私もその一人で、毎回、試行錯誤を繰り返していますが、うまくいったケースを参考までにメモとして残しておきます。なお、これでうまくいかないケースやセキュリティ上大丈夫かなどの問題も想定されるので、記事の内容の適用については、あくまで自己責任でお願いします。

<hr>

<h4>1. settings.pyを本番環境用に修正する</h4>

settings.py（重要な箇所のみコードを抽出しています）はデフォルトというかローカル開発環境では、以下のようになっていると思います。ローカル開発環境で動作させるだけであれば、アプリを追加した場合にアプリ名をINSTALLED_APPSに追加する程度の修正のみだと思います。（今後ローカル環境と本番環境で使い分けるため、ローカル環境用のものは、settings_local.pyのようにファイル名を変えておくことをおすすめします。）

```python:settings_local.py

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

DEBUG = True

ALLOWED_HOSTS = []

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
#　ローカル環境でも、アプリを追加（manage.py startapp ＜アプリ名＞）した場合、
#  ここにアプリ名を登録していると思いますが、それはデプロイ後もそのまま維持します。
    'test_app',

]

ROOT_URLCONF = 'apps.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

STATIC_URL = '/static/'


```


Herokuにデプロイして動作させるためには、上記のローカル開発環境用の設定ファイルに何箇所か修正を入れる必要があります。以下が、実際に私がherokuへのデプロイに成功したファイルです。
おそらくポイントは大きく３つ。１つ目は、ホワイトノイズを使えるようにすること、２つ目は、テンプレートの場所の指定、３つ目は、静的ファイルの場所の視点、です。
このあたりをミスすることでエラーが発生しているように思いますので、ご自身の環境にあわせてチェックをされることをおすすめします。

```python:settings.py

from pathlib import Path
import os
import whitenoise

#修正
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

#追加
SETTINGS_PATH = os.path.dirname(os.path.dirname(__file__))

#ここは、最初はTrueでやってみて、エラーが出ないか確認してからFalseに変えるのも一案。
#（Falseにするとエラーがあったときに原因の究明ができない）
DEBUG = False

#デプロイしたホスト名を記載する
ALLOWED_HOSTS = ['abc.fff.com']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

#アプリ名はそのまま。もし動かない場合には、'test_app.apps.Test_appConfig'と
#する必要があるかもしれません。
    'test_app',

]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

#WhiteNoiseを追加。SecurytyMiddlewareがその前に入っているのことを確認しましょう。
#settings.pyの頭にimport whitenoiseとしてモジュールをインポートしておく。
    'whitenoise.middleware.WhiteNoiseMiddleware',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',

#ここがポイント。テンプレートディレクトリをこのような形で明示してやることが必要。
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]


# データベースは特にいじらなくても、問題なく動きました。HerokuはPostgreSQLに対応している
# ので、そちらに移植するという選択肢もあるかもしれない。
DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
}

#ここからがポイント。静的ファイルの扱いは常にトラブルになりがちなので慎重に設定しましょう。
#ここは特に変更する必要なし。
STATIC_URL = '/static/'

#これを新たに追加する必要があります。静的ファイルのルートを指定します。
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# STATICFILES_DIRSの設定をしているケースもあるようですが、試行錯誤した結果、個人的には
# 不要ではないかと思います。以下はなくても動きました。
# STATICFILES_DIRS = (
#    os.path.join(BASE_DIR, 'static'),    
#)

#これも追加。Whitenoiseを使うために必要らしい。
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

```
<h4>2. Heroku上の環境構築に必要な設定ファイルの準備</h4>
３つのファイルを準備します。runtime.txtはPythonのインストール用（これは不要との説もあります。）、Procfileは、Heroku上でmanage.py runserverを実行して動かすために必要なファイル（説明が間違っているかも）、requirements.txtは、モジュールのインストールに必要なファイルです。参考までに、私が使用しているそれぞれのファイルを掲載しておきます。runtime.txtに記載するPythonのバージョンは、Herokuで対応しているものが限定的なので、Herokuのサイトでバージョンを確認された方が良いと思います。


```python:runtime.txt
python-3.8.10
```

```python:Procfile
web: gunicorn quiz.wsgi --log-file -
```

```python:requirements.txt
dj-database-url==0.5.0
Django==2.2.6
django-heroku==0.3.1
gunicorn
psycopg2==2.8.4
pytz==2019.3
sqlparse==0.3.0
whitenoise==4.1.4
```
<h4>3. Herokuにデプロイ</h4>
まず、PythonのプロジェクトをHerokuにデプロイする際に、はじめての方は公式サイトのチュートリアルにざっと目を通してなんとなく感覚をつかむことをオススメします。
https://devcenter.heroku.com/ja/articles/getting-started-with-python

Herokuのアカウント作成方法は各種サイトに掲載されていると思いますので、ここでは省略したいと思います。また、GitHubとリンクする方法もありますが、とりあえず作ったものをアップするだけの方法を紹介したいと思います。バージョン管理が必要な場合には、GitHubを使ってデプロイをしてみてください。

```
＜（参考）Heroku CLIのインストール（MACの場合）＞
$ brew install heroku/brew/heroku

＜（参考）アカウント作成後のログイン＞
$ heroku login

＜（参考）プロジェクト作成　※任意のプロジェクト名が自動生成されます。
Herokuのウェブサイトから作成しても良いかも。＞
$ heroku create　

＜アプリ名を表示＞
$ heroku apps

＜Gitと特定のアプリを連携＞
$ heroku git:remote -a アプリ名

$ git init
$ git add .
$ git commit -m "initial commit"
$ git push heroku master

＜アプリを動かすコマンド＞
$ heroku ps:scale web=1

＜アプリを開くコマンド＞
$ heroku open

＜アプリを止めるコマンド＞
$ heroku ps:scale web=0

＜（参考）マイグレーションと特権管理者の設定＞
$ heroku run python manage.py migrate
$ heroku run python manage.py createsuperuser

```

<h4>（参考）Collectstaticについて</h4>
自動的にHerokuではCollectstatic（静的ファイルを自動的に収集）作業をやってくれるのですが、どうもエラーが出るという記事をよく見るように思います。私はエラーが出なかったのですが、ローカル開発環境下でcollectstaticはやっておいて、Heroku上では行わないという手法もあるようです。その場合の無効化コマンドは以下の通り。

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