2023/02/01現在、herokuは無料プランの提供を終了しており、有料プランのみの提供となっています。
無料でサーバーを立てられるherokuでDjangoを使ったアプリケーションを構築しようとしたところ、たくさんのトラップに引っかかったので、備忘録としてまとめることにしました。
0. 前置き
目的
- herokuにDjangoアプリケーションを立てたい
- リポジトリはGitHubに置いておきたい
- Djangoで使うDBはMySQLがいい
今回は以上の目的を達成するための流れを一通り説明します。
前提知識
- ターミナルの基本操作ができること
- pythonの環境を整えていること
- djangoの基本的な使い方を知っていること
ローカル環境
環境 | 項目 |
---|---|
OS | macOS BigSur 11.5.2 |
Python | 3.9.7, venv(環境管理), pip(パッケージ管理) |
Django | 3.2.7 |
heroku CLI | heroku/7.59.0 darwin-x64 node-v12.21.0 |
その他
- プロジェクト名は
[heroku-pj]
または[heroku_pj]
と記載しています。各自の設定に置き換えてください - herokuコマンドに必須の
-a
オプションは省略しているので、各自で補完してください
1. Pythonの設定
まずはローカルの環境を整えます。
1-1. 仮想環境(venv)の用意
※Pythonの環境整備は宗派が分かれるので参考程度で。
% python -m venv .venv
% source .venv/bin/activate
# 警告がしつこく出るのでupgradeする
% pip install -U pip
1-2. 必要なライブラリのインストール
必要なライブラリは以下の通りです。(バージョンは執筆当時の最新版です)
asgiref==3.4.1
dj-database-url==0.5.0
Django==3.2.7
django-heroku==0.3.1
gunicorn==20.1.0
mysql==0.0.3
mysqlclient==2.0.3
psycopg2==2.9.1
pytz==2021.1
sqlparse==0.4.1
whitenoise==5.3.0
-
psycopg2
のインストールがうまくいかない場合は以下のページを参考にしてください
1-3. djangoプロジェクトの作成
今回はプロジェクトのルートをgit管理したいので、作ります。
アプリケーションは今回は作らなくても良いです。
% django-admin startproject [heroku_pj]
% cd [heroku_pj]
1-4. 各種ファイルの作成
.gitignore
必要なものがあれば適宜追記してください。
__pycache__
.DS_Store
local.py
db.sqlite3
requirements.txt
以下のコマンドで生成します(上記のrequirements.txtをコピペしても良いですが、最新版にしておくことをお勧めします)
% pip freeze > requirements.txt
Procfile
herokuのビルドに必要です。
web: gunicorn heroku_pj.wsgi --log-file -
runtime.txt
heroku上のPythonバージョン指定に必要です。
バージョンはこちらのページで最新の対応状況を確認してください。
python-3.9.7
1-5. settings.pyの分離
開発環境(ローカル)と本番環境(heroku上)ではデータベース等の設定が異なりますので、ファイルを分離しておいた方が良いです。
本記事では分離することを前提としてコードを書いているので、分離しない人は1-5, 1-6をスキップしてください。
1-5-1. フォルダ構造
- [heroku_pj]-ルート
- [heroku_pj]
- settings
- __init__.py
- base.py
- local.py
- production.py
- __init__.py
- asgi.py
- urls.py
- wsgi.py
- settings
- manage.py
- (以下省略)
- [heroku_pj]
1-5-2. base.py
デフォルトのsettings.py
から以下の項目を除きます。
-
DEBUG
,ALLOWED_HOSTS
,SECRET_KEY
,DATABASES
-
SECRET_KEY
は中身をコピー&メモしておくこと(あとで使います)
-
また、以下の項目を変更しておきます(差分のある項目のみ表示)
# settingsの階層が1つ深くなるのでさらに親ディレクトリを取る
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# whitenoiseのミドルウェアをこの位置に追加する
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
(省略)
]
LANGUAGE_CODE = 'ja-jp'
TIME_ZONE = 'Asia/Tokyo'
# 以下はwhitenoiseとcollectstaticに関連して必要な設定
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
- 参考: whitenoiseとは
1-5-3. local.py
BASE_DIR
は base.py
で定義しているので明示する必要はありませんが、気持ち悪い人は書き加えてください。
import os
from .base import *
DEBUG = True
# ここは各自でよしなにしてください
ALLOWED_HOSTS = ['127.0.0.1',]
SECRET_KEY = '[元のSECRET_KEYをそのままコピペ]'
#settings.pyからそのままコピー
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
1-5-4. production.py
BASE_DIR
については同上。
また、多くの値を環境変数から取得していますが、その設定については後述します。
import os
import django_heroku
import dj_database_url
from .base import *
DEBUG = False
# ['*']でもいい
ALLOWED_HOSTS = ['127.0.0.1', '.herokuapp.com']
# 秘密鍵はファイルに書かない
SECRET_KEY = os.environ['SECRET_KEY']
DATABASES = {
'default': {
# localと異なり、mysqlのエンジンを用いる
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
# これを設定しないとMySQLのWARNINGが出る
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
# 以下はあとで値を設定する
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USERNAME'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOSTNAME'],
'PORT': os.environ['DB_PORT'],
}
}
# 補足参照
db_from_env = dj_database_url.config(conn_max_age=600, ssl_require=False)
DATABASES['default'].update(db_from_env)
django_heroku.settings(locals(), databases=False)
-
MySQLを使わず(heroku標準の)PostgreSQLを使用したい場合、
DATABASES['default']['ENGINE']
の値は以下に変更になります'django.db.backends.postgresql_psycopg2'
-
dj_database_url.config()
において、ssl_require=False
を指定しないとdjango_heroku.settings()
でエラーが出ます- これはdjango_herokuがsslをサポートしていないのに、読み込み時に勝手にssl設定を読み込もうとすることが原因のようです
- 参考: Django Heroku, server does not support SSL, but SSL was required
1-6. manage.py/wsgi.pyの書き換え
開発環境と本番環境で適切なsettingsを読み込むために必要です。
1-6-1. manage.py
書き換え前(抜粋、main関数の最初)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "[heroku_pj].settings")
書き換え後
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "[heroku_pj].settings.local")
1-6-2. [heroku_pj]/wsgi.py
書き換え前(抜粋)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "[heroku_pj].settings")
書き換え後
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "[heroku_pj].settings.production")
ここまで長くなったので続きは別記事へ。