メモ。
以前、Heroku の Getting Started with Python on Heroku チュートリアルをやった時に
一応、最後まで進めることはできたんだけど、heroku local
でローカルでアプリを立ち上げた時 /db
にアクセスするとエラーになってしまい、そこだけうまくいってなかった。
/db
に対応するビューの処理は
def db(request): greeting = Greeting() greeting.save() greetings = Greeting.objects.all() return render(request, 'db.html', {'greetings': greetings})
なので、Postgres の設定まわりがうまくいってないんだろうとは思いつつ結局原因を突き止められずにいたが、その後ようやくわかったのでメモ。
TL;DR
clone してきたリポジトリの README に書いてある通り、下記のコマンドを実行すればよかった。
(実行には foreman という gem が必要になるので、
なければ gem install foreman
でインストールする)
$ createdb python_getting_started $ foreman run python manage.py migrate
前提:Postgres をインストールする
前提として、Postgres が正しくインストールされていることを確認する。
自分は公式ドキュメントに書かれている Postgres.app ではなく、Homebrew から入れてた。
$ brew install postgresql
「Homebrew Postgres」とかでググるとこのへんの記事が見つかるんだけど、
Homebrewを使ったPostgreSQLのインストール(Mac OS Lion) - Qiita
initdb
などは brew install
した時に自動的に設定されてるらしく不要だった。
ただ、Heroku 公式ドキュメントのここにある通り、DATABASE_URL
を設定しておいた方が良い。
https://devcenter.heroku.com/articles/heroku-postgresql#local-setup
使用しているシェルに合わせて設定ファイルに以下を記載する。
(自分の場合は zsh なので .zshrc
に記載)
export DATABASE_URL=postgres:///$(whoami)
Postgres.app を入れた場合はどういう設定が必要なのか未確認。
ただ、少なくとも psql
などのコマンドへのパスが通ってないので設定する必要がある。
ref. Using Command Line Tools with Postgres.app
export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/9.4/bin
最初のエラー
/db
にアクセスした時に最初に表示されたエラーがこれ。
OperationalError at /db
FATAL: database "python_getting_started" does not exist
エラーメッセージの通り、python_getting_started
というデータベースが存在しないのが原因。
そのため、
$ createdb python_getting_started
でデータベースを作成してやれば OK。
では、python_getting_started
というデータベース名はどこからきたのかというと
リポジトリ内に .env
があり、そこに書かれていた。
DATABASE_URL=postgres:///python_getting_started
.env
についてはチュートリアルの Define config vars にも出てきたが、
ここに書いた変数は heroku local
した時に自動的に読み込まれ、環境変数にセットされる。
次のエラー
無事にデータベースを作成した後発生したのが次のエラー。
ProgrammingError at /db
autocommit cannot be used inside a transaction
これはローカルだけでなくデプロイしたアプリでも最初に発生するエラーで、
テーブルが作られていないのが原因。
ref. https://devcenter.heroku.com/articles/getting-started-with-python#provision-a-database
Accessing it will yield an error though, because while the database is configured, the tables have not been created. Run the standard Django
manage.py migrate
to create the tables.
ということでチュートリアルでは
$ heroku run python manage.py migrate
を実行してうまくいったので、ローカルでも同じコマンドを実行する。
$ python manage.py migrate Operations to perform: Synchronize unmigrated apps: staticfiles, messages, hello Apply all migrations: admin, contenttypes, auth, sessions Synchronizing apps without migrations: Creating tables... Creating table hello_greeting Running deferred SQL... Installing custom SQL... Running migrations: Rendering model states... DONE Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying sessions.0001_initial... OK
なんとなく全部うまくいってる感じがしたので再度 /db
にアクセスするも、改善していない。
これは、python manage.py migrate
だけだと .env
で指定している DATABASE_URL
を考慮せず、.zshrc
で指定した DATABASE_URL
が指すデータベースに対してテーブルを作成しているからのよう。
で、それを解決するには foreman という Ruby Gem が必要。
foreman run
コマンドについてはちゃんと調べ切れていないが、foreman run
に続いて実行したいコマンドを入力すると
.env
を考慮した状態でコマンドが実行される。
$ foreman run python manage.py migrate Operations to perform: Synchronize unmigrated apps: staticfiles, messages, hello Apply all migrations: admin, contenttypes, auth, sessions Synchronizing apps without migrations: Creating tables... Creating table hello_greeting Running deferred SQL... Installing custom SQL... Running migrations: Rendering model states... DONE Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying sessions.0001_initial... OK
この状態で /db
にアクセスすると正しく動いてるのがわかる。
よかった。
TODO
python manage.py migrate
でやっていること
Django の話。たぶんこのへん。
Migrations | Django documentation | Django
- foreman について
heroku local
などのコマンドも、内部で実行しているのはこの foreman というコマンドらしい。
Running Apps Locally | Heroku Dev Center
なので、heroku local
のかわりに
$ foreman start web
としてもアプリが起動する。
(2015/12/13追記)
こんなエラーも出た。