Skip to content

Instantly share code, notes, and snippets.

@nabucosound
Last active July 12, 2022 10:54
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nabucosound/6923147 to your computer and use it in GitHub Desktop.
Save nabucosound/6923147 to your computer and use it in GitHub Desktop.
Heroku mini how-to for deployment of Django projects

Deploy a Django app on Heroku

In this example we will deploy a test environment of the app "myproject".

Prerequisites

Heroku toolbelt for deployment:

https://toolbelt.heroku.com/

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

Manage.py and .env

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

Settings.py

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,
        },
    }
}

Setup

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment