Rubyに負けるな！HerokuでPython(Django)動かす方法

タイトルの通り、HerokuというとどうもRubyというかRailsなイメージがある。
だけど、RubyだけじゃなくてPythonも使えちゃうんだよ！ということで、PythonのフレームワークであるDjangoを動かす方法を投稿してみようかなと思います。

## Djangoって？

Python製のいわゆるフルスタックWebフレームワークで、このフレームワークにWebアプリを作るために必要なものがすべて詰まってます。
例えばJavaだと

* AppサーバーとしてのTomcat
* MVCフレームワークとしてSpring MVC
* DBアクセスとしてのHibernte
* などなど

と色々組み合わせて作っていく必要がありますが(最近ならJava EEだけで頑張ることもできるかも？)、Djangoは基本的にDjangoだけで開発が可能です。

コーディングはもちろんPythonで行うので、Pythonが使える、もしくはこれからPythonを勉強してみたい　という人には、お勧めです。
なお、明日はPython製の別のフレームワーク、[Flask](http://qiita.com/tags/flask)に関する記事を[kounoike](http://qiita.com/kounoike)さんが書いてくれる様なので、そちらも参考にしてみるといいかもしれません。

## DjangoをHerokuにデプロイする際に考慮する点

僕が主にハマったポイントです。ここでは、Herokuを本番環境、実運用する環境とする前提で話をします。

### Pythonのバージョン

heroku上のデフォルトのPythonのバージョンは2.x系です。3.x系を利用したい！という場合は、herokuにその旨伝えてあげる必要があります。

### デバッグモード

Djangoは、デバッグモードというものを備えていて、環境を作った際はデフォルトでその機能がOnになっています。
これがOnになっている事で、例えばエラーになった際に詳細な内容を表示してくれます。以下は404エラー例。現在URLとして認識しているURLが表示されていますが、これが運用させるページで表示されてしまうのは困りものです。
![デバッグ時の404エラー例](https://qiita-image-store.s3.amazonaws.com/0/35254/8e5d302c-c2ff-77af-bfe9-010ac7af9e75.png)

### データベース

Djangoでは、設定を変更しない限り、開発中はSQLiteをDBとして利用しています。ただし、Heroku上で利用できるのは基本的にPostgresです。なので、DBの設定も変更してあげる必要があります。

### Appサーバー

フルスタックフレームワークという事で、Django自身もAppサーバーとしての機能を持っています。
しかし、あくまでも開発用という位置付けで、実運用する際はAppサーバーとしてカリカリにチューニングされた、専用のものを用いる事が推奨されます。

### staticファイルの取り扱い

Appサーバーでは、基本的にアプリケーションを動かす為のサーバーなので、staticファイルの取り扱いが得意ではありません。他の言語のAppサーバーでも、staticファイルを取り扱う為にApacheを置いたりnginxを置いたりするかと思います。
この点についても、考慮が必要です。

## 解決策

僕はこうやって動かしてる！という解決策なので、もし「こうやったほうがいい！」などありましたら突っ込みよろしくお願いします。

### Pythonのバージョン

これは簡単です。プロジェクトのカレントフォルダにruntime.txtというファイルを用意し、そこで以下のようにPythonのバージョンを指定してあげるだけです。

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

![runtime.txt](https://qiita-image-store.s3.amazonaws.com/0/35254/6e72842d-791f-07fc-8fcf-14f920aaa553.png)
注意点としては、利用できるバージョンは決まっているので、以下のページを参考にして利用するバージョンを選んでください。
[Specifying a Python Runtime](https://devcenter.heroku.com/articles/python-runtimes)

### デバッグモード

デバッグモードの設定は、`settings.py`で指定します。しかし、herokuにpushする際に変更して、ローカルで開発する際は戻して・・・とやると大変です。
ので、僕の場合は以下のように、ホスト名(マシン名)にlocalが入っている場合のみデバッグモードになる様にしています。
こちらは僕の開発環境が"hogehoge.local"といった名前を付けている為であり、ご使用のホスト名に合わせてlocalの部分は変更してください(逆に、heroku側のマシン名で指定するのもありか)

```py3:settings.py

if 'local' in hostname:
    DEBUG = True
    TEMPLATE_DEBUG = True
else:
    DEBUG = False
    TEMPLATE_DEBUG = False
    ALLOWED_HOSTS = ['*']
```

### データベース

こちらも、`settings.py`で指定することになりますが、環境に合わせて書き換えるといったことはしたくない。
そこで、以下のような記載を行うことにします。


```py3:settings.py

if 'local' in hostname:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
else:
    import dj_database_url
    DATABASES = {
        'default': dj_database_url.config()
    }
```
ここで一つポイントとなるのが、

```py3:

    import dj_database_url
    DATABASES = {
        'default': dj_database_url.config()
    }
```

の部分。dj_database_urlなるAPI(pipでインストール可能)を用いることで、コード内に接続先やユーザー名、パスワードなど記載する必要がないんです。
これは衝撃でした。

### Appサーバー

PythonのWebアプリケーションフレームワークは、[WSGI](http://ja.wikipedia.org/wiki/Web_Server_Gateway_Interface)という規格があって、こちらに準拠したサーバーであればどれを利用しても構いません。
herokuのドキュメントでは、gunicornを用いた説明があるので、そちらに乗っかることにします。

[Deploying Python Applications with Gunicorn](https://devcenter.heroku.com/articles/python-gunicorn)

こちらを利用するには、pipでgunicornをインストールし、settings.pyのINSTALLED_APPSの末尾にgunicornの記載を追加します。

```py3:settings.py

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.sites',
    'django.contrib.staticfiles',
    'django.contrib.sitemaps',
    'プロジェクト名',
    'gunicorn',   ## ←この行追加
)
```

そして、開発時は

```
$ python manage.py runserver 0.0.0.0:8080
```

といった形で起動していたものを、後述の方法(Procfileの記載)によって`manage.py`ではなくgunicornで起動することになります。

### staticファイルの取り扱い

これがなかなか情報を見つけられなくて苦労しました。
結論で言うと、Whitenoiseというものを利用します。

[Django and Static Assets](https://devcenter.heroku.com/articles/django-assets)

pipでwhitenoiseをインストールした後、`settings.py`を上のリンクの説明に従って変更します。
そして、`settings.py`がある場所と同じフォルダにwisgi.pyというファイルを用意し、そこにリンクにも記載のある以下の内容を記述します。

```py3:wsgi.py

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise

application = get_wsgi_application()
application = DjangoWhiteNoise(application)
```

そして、gunicornも含め、設定したものを利用して起動されれる様に、Procfileに以下の様に記載します。

```text:Procfile

web: gunicorn --env DJANGO_SETTINGS_MODULE=プロジェクト名.settings プロジェクト名.wsgi --log-file -
```

こちらの設定で、herokuのリポジトリにpushすれば、起動するはずです！

## パフォーマンスとかどうなの？？

上記設定でデプロイしたアプリケーションを先日リリースし、リリース初日には２万PVほどありましたが、無料枠の範囲で問題なく元気に動いてました。いや、herokuほんとすごい。

以下にアプリケーションを実際に作った際の経緯を書いたブログのリンクを置いておきますので、こちらも参考にしていただけたらなと思ってます

[性の悩みを解決する為のWebサービスをつくってみました](http://nakazye.hatenablog.com/entry/2014/11/03/004922)

＞＞実際に動かしてるサービス
[Love Points](http://www.lovepoints.pink/)

## 追記

heroku & Djangoで作った、実際に運用しているサービス(↑のとは別物)のソースコードをgithubにアップしました。

構成等、参考になれば幸いです（汚いソースですが・・・）

https://github.com/nakazye/ProgrammerProfile/

## お次は・・・

明日、12/8のHeroku Advent Calendar 2014は[kounoike](http://qiita.com/kounoike)さんのFlaskに関するお話です！Pythonネタが続くということで、ワクワクしております。

そして、記事に触発されて、Pythonでアプリケーション作る人がもっともっと増えたらななんて思ってます。

[kounoike](http://qiita.com/kounoike)さん、明日の記事楽しみにしてます！！