Deploying Django to Heroku with PostgreSQL database is simple but we’ll miss some simple stuff and stuck.

This article demystify those into simple steps.

Initial Installation and setup

Before changing any files we need to install require packages.

Modules for development setup

Decople and Psycopg2

pip install python-decouple
pip3 install psycopg2 

Decouple module helps us to handle the environment variables for the local development

PostgreSQL database adaptor for python.

Heroku modules

Following modules are Heroku dependent gunicorn, django-heroku, whitenoise, dj-database-url

white noise used to serve the static contents in Heroku and gunicorn is a application server for django in Heroku.

pip install gunicorn
pip install django-heroku
pip install whitenoise
pip install dj-database-url

Environment variables

create .env in root folder(where manage.py is there) location. Add the database configuration, secret key and and debug

DATABASE_NAME = 'interview'
DATABASE_USER = 'postgres'
DATABASE_PASSWORD = 'admin@1234'
DATABASE_HOST = '127.0.0.1'
DATABASE_PORT = '5432'
SECRET_KEY= 'your-secret-key'
DEBUG = True

create gitignore file to avoid committing system credentials and unwanted files

create .gitignore in root folder add below lines to it

.env
*.pyc

Now initial setup is done we need to change our application configuration to make it run.

1. settings.py

First we need to modify the settings.py separating setting settings will another article(base, development, production). To make it simple these change will be in single file.

Change the debug, secret-key, database config, static from from settings.

from decouple import config, UndefinedValueError

import config on top

Update the debug and secret key

try:
  DEBUG = config('DEBUG')
except UndefinedValueError:
  DEBUG = False

Allowed Host

If debug is false allowed host to added . Add Heroku server URL in the end if you want specific host to be allowed either allowed any host

ALLOWED_HOSTS = ['0.0.0.0', 'localhost', '127.0.0.1']

or

ALLOWED_HOSTS = ['*']

Add PostgreSQL to Database

Separate the Database config for development and server

if DEBUG:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': config('DATABASE_NAME'),
            'USER': config('DATABASE_USER'),
            'PASSWORD': config('DATABASE_PASSWORD'),
            'HOST': config('DATABASE_HOST'),
            'PORT': config('DATABASE_PORT'),
        }
    }
else:
    import dj_database_url
    # set server database configuration here
    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.postgresql_psycopg2",
            'NAME': 'fisdomapp',
            'USER': 'name',
            'PASSWORD': '',
            'HOST': 'localhost',
            'PORT': '',
        }
    }
    db_from_env = dj_database_url.config(conn_max_age=500)
    DATABASES['default'].update(db_from_env)

Now run the django server and validate everything works fine.

Static Section

Every app static folder can be traced by django using staticfiles_storage. It’s similar to Template settings.

STATIC_URL = where the static files will server in local development

STATIC_ROOT = collect all static files for deployment (This need be Absolute path)

e.g,

STATIC_ROOT = os.path.join(BASE_DIR, “static”)

STATICFILES_DIRS = if app has Additional static files need to give in this it will be searched during findstatic and collectstatic commands.

create new folder in root folder location with the name ‘static’ and run below command

python manage.py collectstatic

This will collect all the static file for deployment and everything from admin to every app.

Add White noise settings in end of the settings to server static files in Heroku.

if not DEBUG:
    MIDDLEWARE += ['whitenoise.middleware.WhiteNoiseMiddleware']
    STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
    import django_heroku
    django_heroku.settings(locals())

Add all the apps to Django core and test it locally . Next section is to adding configuration for heroku deployment.

2. Procfile

Create new Procfile in the root folder and add the above line . App name changes according to your django-admin app. My app name is core andwsgi file available there. Usually you have to give settings.py folder name.

web: gunicorn core.wsgi --log-file -

Heroku run the commands before server start app that are all mention inprocfile. We need to define server and worker(celery) here.

What ever the name your settings.py have e.g., sample/wsgi.py then web: gunicorn sample.wsgi –log-file -

3. requirements.py

We need to heroku to install our project dependency packages while building project. That we do by simple python run the below command in root of the project where (manage.py) is available

pip freeze > requirements.txt

This will generate the project dependency packages unfortunately with other packages depended with your depedency package. If you what are all added you can remove them else leave as it.

sample:

dj-database-url==0.5.0
Django==3.0.6
django-heroku==0.3.1
gunicorn==20.0.4
psycopg2==2.8.5
python-decouple==3.3
whitenoise==5.1.0

4. Heroku Login and Setup

Login to Heroku and create new app. Next go to root folder of location and run below command

Note: heroku cli need to install before running this

heroku login

After login you can use below commands

Create new git init folder if

git init

Add remote Heroku

heroku git:remote -a django-postgres-demo 

5. Adding PostgreSQL Addon

Add PostgreSQL database to the current app

 heroku addons:create heroku-postgresql:hobby-dev

###6. Migrate the change the Heroku PostgreSQL

heroku run python manage.py migrate

This will apply the local migrations to Heroku PostgreSQL

7. Add secret-key to Heroku

go to settings -> Revel config

Click Add -> new config variable SECRET_KEY

Finally push the changes to GitHub and Heroku

git push heroku master

If there is no issue. run below commanD

8.Scale the Heroku web app

heroku ps:scale web=1

This command start the app after it’s deployed.

heroku logs --tail 

Use above command to find out the error if still not clear use below technique

NOTE: If you face 500 error enable debug true in settings.py find the error then update the debug.

SAMPLE Code: https://github.com/armsarun/django-heroku

Reference Links:

Django Static File Handling = Python Anywhere