Install Heroku CLI
Sign Up to Heroku
After installing the Heroku CLI, open a terminal and login to your account:
$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
heroku: Waiting for login... ⣻
You're redirected to your browser and you login to Heroku with Heroku CLI and get a success message on your terminal
Creating App
First make sure you are in the root directory of the repository you want to deploy
Next create the heroku app from the terminal:
heroku create <your-app>
Preparing the Application
Assumptions
- You're familiar with the basics of Django. eg. concept of apps, settings, urls, basics of databases.
- You have a Django application that you want to deploy to Heroku.
- You are familiar with virtual environments
- Your deployment Database is PostgreSQL
You will have to install several packages that will come in handy:
- django-heroku
pip install django-heroku
- gunicorn
pip install gunicorn
- decouple
pip install python-decouple
- DATABASE_URL
pip install dj-database-url
- whitenoise
pip install whitenoise
You will then add the following files in your application
- Add a
Procfile
in the project root; - Add
requirements.txt
file with all the requirements in the project root; - Add
requirements.txt
withpip freeze > requirements.txt
- A
runtime.txt
to specify the correct Python version in the project root; - Configure
whitenoise
to serve static files.
Now we go through each one of them
Procfile
Heroku apps include a Procfile that specifies the commands that are executed by the app’s dynos.
Create a file named Procfile in the project root with the following content:
web: gunicorn your_project_name.wsgi
runtime.txt
This file contains the python version you are using for heroku to use, create runtime.txt
in your project root and add your python version in the following format:
python-3.8.12
You can specify which runtime to use for your app. List of Heroku Runtimes
Configuring Whitenoise: Django Static Files settings
It turns out django does not support serving static files in production. However, WhiteNoise project can integrate into your Django application, and was designed with exactly this purpose in mind.
Lets first configure static related parameter in settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
Then add this line of code in the middleware section
MIDDLEWARE_CLASSES = (
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
'whitenoise.middleware.WhiteNoiseMiddleware',
...
Add the following setting to settings.py in the static files section to enable gzip functionality.
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# configuring the location for media
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Configure Django App for Heroku.
django_heroku.settings(locals())
python-decouple and dj-database-url
Python Decouple is a must have app if you are developing with Django. It’s important to keep your application credentials like API Keys, tokens and passwords.
dj-database-url is a simple Django utility that holds your Postgres database url
.env
Firts create a .env
file and add it to .gitignore
so you don’t commit any sensitive data to your repository. Below is an example of configurations you can add to the .env
file.
# An example, don't share your.env settings
SECRET_KEY='342s(s(!hsjd998sde8$=o4$3m!(o+kce2^97kp6#ujhi'
DEBUG=True
DB_NAME='db_name'
DB_USER='user'
DB_PASSWORD='db_password'
DB_HOST='127.0.0.1'
MODE='dev'
ALLOWED_HOSTS='<app name in heroku>.herokuapp.com'
DISABLE_COLLECTSTATIC=1
We then edit settings.py to enable decouple to use the .env configurations.
import os
import django_heroku
import dj_database_url
from decouple import config,Csv
MODE=config("MODE", default="dev")
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
# development
if config('MODE')=="dev":
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST'),
'PORT': '',
}
}
# production
else:
DATABASES = {
'default': dj_database_url.config(
default=config('DATABASE_URL')
)
}
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
Deploying the app to Heroku
Create a postgres addon to your Heroku app
heroku addons:create heroku-postgresql:hobby-dev
Next we log in to Heroku dashboard to access our app and configure it
Add all your configurations in .env
file directly to Heroku by running this command.
heroku config:set $(cat .env | sed '/^$/d; /#[[:print:]]*$/d')
Remember to first set DEBUG to False and confirm that you have added all the configuration variables needed. Click on the Settings menu and then on the button Reveal Config Vars
Pushing to Heroku
Confirm that your app is running as expected before pushing. Runtime errors will cause deployment to fail so make sure you have no bugs and you have all the following; Procfile
, requirements.txt
with all required packages and runtime.txt
.
Commit all the changes we have made and then:
git push heroku master
- If you are using main as the branch, change master to main
If you did everything correctly then the deployment should be done after a while with an output like this
Enumerating objects: 94, done.
Counting objects: 100% (94/94), done.
Delta compression using up to 8 threads.
Compressing objects: 100% (84/84), done.
Writing objects: 100% (94/94), 3.35 MiB | 630.00 KiB/s, done.
Total 94 (delta 24), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Python app detected
remote: -----> Installing python-3.6.6
remote: -----> Installing pip
remote: -----> Installing requirements with pip
remote: Collecting config==0.3.9 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 1))
remote: Downloading https://files.pythonhosted.org/packages/0a/46/186ac016f3175211ec9bb4208579bc6dc9dd7dc882790d9f281533b83b0f/config-0.3.9.tar.gz
remote: Collecting dj-database-url==0.5.0 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 2))
remote: Downloading https://files.pythonhosted.org/packages/d4/a6/4b8578c1848690d0c307c7c0596af2077536c9ef2a04d42b00fabaa7e49d/dj_database_url-0.5.0-py2.py3-none-any.whl
remote: Collecting Django==1.11 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 3))
remote: Downloading https://files.pythonhosted.org/packages/47/a6/078ebcbd49b19e22fd560a2348cfc5cec9e5dcfe3c4fad8e64c9865135bb/Django-1.11-py2.py3-none-any.whl (6.9MB)
remote: Collecting django-bootstrap3==10.0.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 4))
remote: Downloading https://files.pythonhosted.org/packages/18/a8/f12d8491155c7f237084b883b8600faf722e3a46e54f17a25103b0fb9641/django-bootstrap3-10.0.1.tar.gz (40kB)
remote: Collecting django-heroku==0.3.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 5))
remote: Downloading https://files.pythonhosted.org/packages/59/af/5475a876c5addd5a3494db47d9f7be93cc14d3a7603542b194572791b6c6/django_heroku-0.3.1-py2.py3-none-any.whl
remote: Collecting gunicorn==19.9.0 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 6))
remote: Downloading https://files.pythonhosted.org/packages/8c/da/b8dd8deb741bff556db53902d4706774c8e1e67265f69528c14c003644e6/gunicorn-19.9.0-py2.py3-none-any.whl (112kB)
remote: Collecting Pillow==5.2.0 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 7))
remote: Downloading https://files.pythonhosted.org/packages/d1/24/f53ff6b61b3d728b90934bddb4f03f8ab584a7f49299bf3bde56e2952612/Pillow-5.2.0-cp36-cp36m-manylinux1_x86_64.whl (2.0MB)
remote: Collecting psycopg2==2.7.5 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 8))
remote: Downloading https://files.pythonhosted.org/packages/5e/d0/9e2b3ed43001ebed45caf56d5bb9d44ed3ebd68e12b87845bfa7bcd46250/psycopg2-2.7.5-cp36-cp36m-manylinux1_x86_64.whl (2.7MB)
remote: Collecting python-decouple==3.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 9))
remote: Downloading https://files.pythonhosted.org/packages/9b/99/ddfbb6362af4ee239a012716b1371aa6d316ff1b9db705bfb182fbc4780f/python-decouple-3.1.tar.gz
remote: Collecting pytz==2018.5 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 10))
remote: Downloading https://files.pythonhosted.org/packages/30/4e/27c34b62430286c6d59177a0842ed90dc789ce5d1ed740887653b898779a/pytz-2018.5-py2.py3-none-any.whl (510kB)
remote: Collecting whitenoise==3.3.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 11))
remote: Downloading https://files.pythonhosted.org/packages/0c/58/0f309a821b9161d0e3a73336a187d1541c2127aff7fdf3bf7293f9979d1d/whitenoise-3.3.1-py2.py3-none-any.whl
remote: Installing collected packages: config, dj-database-url, pytz, Django, django-bootstrap3, whitenoise, psycopg2, django-heroku, gunicorn, Pillow, python-decouple
remote: Running setup.py install for config: started
remote: Running setup.py install for config: finished with status 'done'
remote: Running setup.py install for django-bootstrap3: started
remote: Running setup.py install for django-bootstrap3: finished with status 'done'
remote: Running setup.py install for python-decouple: started
remote: Running setup.py install for python-decouple: finished with status 'done'
remote: Successfully installed Django-1.11 Pillow-5.2.0 config-0.3.9 dj-database-url-0.5.0 django-bootstrap3-10.0.1 django-heroku-0.3.1 gunicorn-19.9.0 psycopg2-2.7.5 python-decouple-3.1 pytz-2018.5 whitenoise-3.3.1
remote:
remote: -----> Discovering process types
remote:
remote: -----> Compressing...
remote: Done: 56.3M
remote: -----> Launching...
remote: Released v6
remote: https://mtr1bune.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/mtr1bune.git
* [new branch] master -> master
Run Migrations
heroku run python manage.py migrate
If you wish to push your postgres database data to Heroku then run
heroku pg:reset
heroku pg:push <The name of the db in the local psql> DATABASE_URL --app <heroku-app>
You can the open the app in your browse.
Last comment
Don't beat yourself up when you find it challenging to memorize language or library syntax. They have documentation for a reason, so feel free to reference it. The syntax will stick to your memory on frequent use.💯✍️
Top comments (0)