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