Edited at

初心者がハマった、初めてのDjangoアプリのHerokuデプロイ

More than 1 year has passed since last update.

諸用事あって、ローカルで作っていたDjangoアプリをHerokuにデプロイすることになったのですが……なにやらやたらと時間がかかってしまったので、その忘備録として


環境


  • Windows10

  • Django 1.11.x

  • python2.7.x


Djangoとは

(こんな記事を見ている時点で知ってはいると思いますが……)DjangoはPython2,3で動くWebフレームワーク……らしい

「らしい」というのは、筆者はWebフレームワークのことを良く知らないが故である。興味のある人は、公式ドキュメントを参考にしてみては……?

参考:Djangoドキュメント


デプロイとは

ローカル環境で作っていたものを、実際の本番環境へ移行すること……たぶん。

DjangoのようなWebアプリは、ただのWebサイトアップロードのように簡単ではなかった……以下、今回のデプロイのおおまかな流れを綴ってゆく。


前提条件

Djangoの習得がまだ……という方は、こちらにいい感じの記事がありましたのでこちらから習得を……!

PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説

Djangoを最速でマスターする


  • 一般的なネットワーク環境(ファイルをアップロードするので)

  • Djangoアプリ完成済み(sqlite3データベース使用)(virtualenv使用済み)

  • CMD(コマンドプロンプト)が使える

  • gitインストール済み

  • Herokuアカウント所有済み


デプロイ

初めてDjangoを用いてWebアプリを作った筆者。

ぬるぬる動くぜDBの動いているぜヒャッホーイとしていたある日、ついにオンラインで動かす日が来たのであった……(物語風)


初期状況

DjangoApp/

 ├ env/ (virtualenv)

 ├ manage.py

 ├ db.sqlite3

 ├ DjangoApp/(最初からあるやつ)

 │ ├ wsgi.py

 │ └ setting.py

 └ App/ (アプリケーション本体)


デプロイ前夜

デプロイをするにあたって、必要なことは何かと調べてみると「.gitignoreにdb.sqlite3(sqliteのデータベース本体)と*.pyc、そしてenv/以下を入れておく」とのこと。

素直に.gitignoreを作り、「git rm -r --cached .」でキャッシュを削除してcommitした

参考: 【Qiita】.gitignore の設定を反映させる


前夜後の状況

DjangoApp/

 ├ env/

 ├ manage.py

 ├ db.sqlite3

 ├ DjangoApp/

 │ ├ wsgi.py

 │ └ setting.py

 ├ App/

 └ .gitignore (New)


デプロイ準備開始

Herokuにファイルをアップロードする際には、どうやら「Procfile(拡張子なし)」「requirements.txt」「runtime.txt」の3種の神器が必要とのことで作成に入る


Procfile

Herokuに「このアプリはこうやって起動してね!☆」というのを伝えるもの(らしい)

とりあえず、いろんな人が書いていた通りに書いてみることにした


Procfile

web: gunicorn DjangoApp.wsgi --log-file -


DjangoAppの部分は各自のアプリケーション名を記述する。

そして、後でこの「gunicorn」とやらをvirtualenvにインストールしないといけないそうで……むぅ、ひと手間ふた手間かかる……


requirements.txt

Herokuに、このアプリケーションを動かすのに必要なモジュールを連絡する必要がある。それに使うのがrequirements.txt。(たぶん)

こいつは簡単。コマンドでvirtualenvを起動したのちに


CMD

pip freeze > requirements.txt 


とすればよい。

以下のようなファイルが出来上がっているはず。


requirements.txt

Django==1.11.1

virtualenv==15.1.0


runtime.txt

Herokuに、今使っているpythonのバージョンを伝えるものだそうで……(こいつもよくわからない)


CMD

python-2.7.x


2.7.xの部分は各自のパソコンにインスツールされているPythonのバージョンをば


三種の神器作成後

DjangoApp/

 ├ env/

 ├ manage.py

 ├ db.sqlite3

 ├ DjangoApp/

 │ ├ wsgi.py

 │ └ setting.py

 ├ App/

 ├ requirements.txt (New)

 ├ runtime.txt (New)

 ├ Procfile (New)

 └ .gitignore


Django-toolbeltのインストール

調べたところ、デプロイには様々な追加モジュールが必要だそうで……先のgunicorn、staticfileを扱うためのdjando-static、データベースを扱うdj_database_urlなど……一つ一つ扱うのが面倒だねーと思っていたところ、なんとこれらをまとめてやってくれる味方を発見!django-toolbeltである……!


CMD

pip install django-toolbelt


としてtoolbeltをインストールする。必要なモジュールは全部そろった……!

……聡明なあなたなら、「こやつ(笑)」と気が付くはず……そう、このタイミングでtoolbeltによってインストールされたモジュールはrequirements.txtに書いていないのである……筆者はこれに気が付かず半日以上も時間を費やしたのであった……

正しくは、このタイミングでもう一度pip freezeをし直してrequirements.txtをアップデートをしましょう!!


toolbeltインストール後のrequirements.txt


requirements.txt

dj-database-url==0.4.2

dj-static==0.0.6
Django==1.11.1
django-toolbelt==0.0.1
gunicorn==19.7.1
psycopg2==2.7.3
pytz==2017.2
static3==0.7.0
virtualenv==15.1.0


まだまだ続くよ!デプロイ準備!


次はデータベース周りのお話。

聞くところによると、Herokuではsqlite3データベースが使えない模様(インストールできないのかしら……?)

そのため、Heroku標準搭載されている(?)Postgresを使う必要がある、とのこと……

……そして、そのためのdj-database-urlである!

setting.pyを開いて、以下の部分を見つけてくる。


setting.py

DATABASES = {

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

このDBに関する記述を、以下のように書き換える


setting.py

if "COMPUTER-NAME" in hostname:

# デバッグ環境
# DEBUG = True // 筆者はデバッグモードの切り替えもここでやってしまった
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
ALLOWED_HOSTS = [] # よくわからんけど、これも大事らしい
else:
# 本番環境
# DEBUG = False
import dj_database_url
db_from_env = dj_database_url.config()
DATABASES = {
'default': dj_database_url.config()
}
ALLOWED_HOSTS = ['*']

こうすると、ローカル環境ではsqlite3を、Heroku環境下ではPostgresを用いてくれる。(らしい)COMPUTER-NAMEは各自のデバイスの名前で。(localと書けば良い、と見かけたのですが自分の環境ではだめでした……)

また、(ほぼ確実に)「hostnameが無いじゃないか馬鹿ヤロメっ!」と怒られた場合はsetting.pyの最初の方に以下を追加しておきましょう。


setting.py

.

from socket import gethostname
hostname = gethostname()
.


wsgiってよくわからん

ローカル環境では一切触ってこなかったwsgi.pyをつい触る時が……!

……と思いきや、以下のように本当に少し弄るだけでおkらしい


setting.py

import os

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

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DjangoApp.settings")
application = Cling(get_wsgi_application())


DjangoAppは各自のプロジェクト名をば。

……結局、wsgi.pyとはなんだったのか(ソレガワカラナイ


最終状況

DjangoApp/

 ├ env/

 ├ manage.py

 ├ db.sqlite3

 ├ DjangoApp/

 │ ├ wsgi.py (modified)

 │ └ setting.py (modified)

 ├ App/

 ├ requirements.txt

 ├ runtime.txt

 ├ Procfile

 └ .gitignore


いざデプロイ!目指すはHeroku!

準備が整ったのでCMDを立ち上げてHerokuへ!


CMD

git add .

git commit -am "Launching now!"

heroku login
> Enter your Heroku credentials.
> Email: hoge@huga.com
> Password (hidden):
> Logged in as hoge@huga.com

heroku create NAME
> https://NAME.herokuapp.com/ | https://git.heroku.com/NAME.git

git push heroku master
> なんか長々としたsomething

heroku run python manage.py migrate
> いつものmigrateコマンドが流れる

heroku open


最後のHeroku openでアプリケーションが開いてくれます。(筆者の場合は初っ端Application Errorでしたけどね……)

以上でおしまい!あとは運用ですね!!お疲れ様でした!!!(疲れた


感想

こんなことに感想を書くのもあれですが……初心者からすると「なんと遠回りな……もっとスマートにできないの??」と思ってしまうくらい大変でした……(´;ω;`)

特に、最新(ver1.11)のリファレンスが少なく……結局、公式の英語ドキュメント読みまくってました(笑)

広がれ、Djangoの輪!


未解決の不具合


壊れる管理サイト

無事Herokuにデプロイ完了……と思いきや、管理サイトが……

無題.png

壊れるなぁ……(´・ω・`)なぜかCSSを読み込んでくれない……

staticファイルを扱うように、setting.pyに以下を追加しましたが……ダメ……っ!


setting.py

STATIC_URL = '/static/'

# Static asset configuration
STATIC_ROOT = 'staticfiles'

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


……ま、気長に修正していきます!