In this example we will deploy a test environment of the app "myproject".
Heroku toolbelt for deployment:
Use heroku way of declaring database settings with dj-database-url:
pip install dj-database-url
PostgreSQL python adapter:
pip install psycopg2
Gunicorn:
pip install gunicorn
Create Procfile
to launch webserver:
web: python manage.py run_gunicorn -b "0.0.0.0:$PORT" -w 3
Replace your manage.py
with this version so that it calls the read_env
function to populate env vars from .env
file at runtime:
#!/usr/bin/env python import os import sys import re def read_env(): """Pulled from Honcho code with minor updates, reads local default environment variables from a .env file located in the project root directory. """ try: with open('.env') as f: content = f.read() except IOError: content = '' for line in content.splitlines(): m1 = re.match(r'\A([A-Za-z_0-9]+)=(.*)\Z', line) if m1: key, val = m1.group(1), m1.group(2) m2 = re.match(r"\A'(.*)'\Z", val) if m2: val = m2.group(1) m3 = re.match(r'\A"(.*)"\Z', val) if m3: val = re.sub(r'\\(.)', r'\1', m3.group(1)) os.environ.setdefault(key, val) if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "yourproject.settings") from django.core.management import execute_from_command_line read_env() execute_from_command_line(sys.argv)
Create your .env
file and populate it with minimum settings:
DEBUG=True SECRET_KEY='phzr0^(oamc0^50jn82j-g$rrrlq+td8b4h%0==wc=r^-2qrdu' DATABASE_URL=postgres://pguser:pgpassword@localhost:5432/dbname
Use this function to map string-version booleans to proper code booleans:
def env_var(key, default=None): """Retrieves env vars and makes Python boolean replacements""" val = os.environ.get(key, default) if val == 'True': val = True elif val == 'False': val = False return val
Add gunicorn
to INSTALLED_APPS:
INSTALLED_APPS = ( ... 'gunicorn', ... )
Get your databse url from the env var and assign it to DATABASES
:
import dj_database_url DATABASES = {'default': dj_database_url.config(default=env_var('DATABASE_URL'))}
Gunicorn seems to need LOGGING
on Heroku, so make sure you have some stuff there:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse' } }, 'handlers': { 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' } }, 'loggers': { 'django.request': { 'handlers': ['mail_admins'], 'level': 'ERROR', 'propagate': True, }, } }
Create new heroku app:
heroku apps:create myproject-test --remote test
Push git repo:
git push test master
Add env vars:
heroku config:add DEBUG=True heroku config:add SECRET_KEY='n=&1@3s@0ma&8ienk&&w6#n6*duzzx16pk)_3qyi-9e$sq*cq+' ...
Initialize database:
heroku run python manage.py syncdb --noinput
Run migrations:
heroku run python manage.py migrate --all
Collect static:
heroku run python manage.py collectstatic --noinput
Create superuser for admin:
heroku run python manage.py createsuperuser
Scale web dyno:
heroku ps:scale web=1
Add backups addon:
heroku addons:add pgbackups
Add user-env-compile to enable automatic collectstatic to S3 (see http://devcenter.heroku.com/articles/labs-user-env-compile):
heroku labs:enable user-env-compile