Skip to content
This repository has been archived by the owner on Sep 5, 2022. It is now read-only.

Django Heroku direct configuration training

mardi08 edited this page Mar 21, 2018 · 3 revisions

Django and Heroku Direct Configuration Guide

CAM2 training


Latest update: March 2018

Your contribution is appreciated: If you find errors / mistakes / information that is not updated, please report it on the repository issue. This guide is subjected to update based on the tools, dependencies and features involved.

NOTE:

  • If you have successfully deploy a Django project to Heroku without any help tools (like travisCI), you may ignore this section. Many new members might have problems with the deployment to Heroku. So, this is a guide to help you figure out what is wrong with your deployment settings by providing a deeper understanding into the code settings of a Django project.
  • Specific configuration setting for packages may differ from each other. A new update on each package may also affect the configuration settings. check the time of the most recent update on this Wiki.

This guide was developed based on this video, video part 1 to 3, and Heroku documentation.

Configuration used the following modules/packages:

  • whitenoise (free version)
  • Django
  • gunicorn

Configuration for the following files:

Testing your default Django Project


  1. Go to your directory where manage.py exist (should be created when you create the project)
  2. run
python manage.py runserver
  1. the terminal tell you the local server such as
http://127.0.0.1:8000/

(your local server might differ) copy and paste this to your browser. if it works, you should see the default Django page that says "Congratulations on your first Django-powered page"

notice that if you go to the admin/ url, you will be directed to the Django admin panel (http://127.0.0.1:8000/admin). This is defined in your wsgi.py.

Directory set up


You need to have a directory to store you static directory (such as CSS, fonts, image, etc) and templates directory. Django required you to have the directory in the exact wordings (case sensitive).

once you get used to Django configuration, you may freely organize your directories in your own fashion. However, many programmers adopted the following directory structure as a standard because it appeared to be neat:

MyProject (root folder)
  • app
    • static
    • templates
  • project_name
    • settings.py
    • __init__.py
    • urls.py
    • wsgi.py
  • manage.py
  • Procfile
  • requirements.txt
  • runtime.txt

static: where you place your CSS, Fonts, Image, etc. (When you deal with many files, you would want each of these to be a separate folder. for now, you can place your CSS file in the static folder)

templates: where you placed all the HTML files.

wsgi.py


This is where the webserver will start. after you created the Django project, you will get the following code in your wsgi.py

"""
WSGI config for demo project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")

application = get_wsgi_application()

the above code basically telling the webserver to look into settings.py as the next step.

since you will be using the whitenoise package, add the following lines

from whitenoise.django import DjangoWhiteNoise

application = DjangoWhiteNoise(application)

urls.py


urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

The above lines is the default Django admin url. This is the place where you define a certain url to direct user to a certain page. if you had accessed the Django admin panel before using the http://127.0.0.1:8000/admin, that was the result of the above configuration of the urls.py.

settings.py


Typical deployment problem: you are not routing the files directory correctly in your settings.py, don't get frustrated easily.

Tips: Try to focus debugging your configuration on how your files are organized and how you are routing to each of the necessary files in your settings.py

when you create your a Django Project, you get a settings.py. Think of the following code like a skeleton file for configuration.

"""
Django settings for testing project.

Generated by 'django-admin startproject' using Django 1.11.9.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!dhcizt49yjgk)e1fw%uw4_3m^qaj)fyzheymm+k_trfv8jk9s'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'testing.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'testing.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
1. Log in to heroku

to log in simply

heroku login: <your Heroku user name>

to specify the name of your app. your app will be created under your_app_name.herokuapp.com

heroku create: <your_app_name>
2. Assumption
  • you have HTML, CSS and Javascript file ready in your local repository.
  • you have pip installed
  • you are trying to do simple deployment of your HTML page to heroku using django configuration.
  • you have vim installed so all file editing is done in vim mode.
  • you have created a Django project
  • the file and folders organization follows this youtube video which was seemed to be the best practice at the time of this writing.
3. Create virtual Environment
virtualenv <your virtual environment name>

example,

virtualenv env

a venv is created in your current directory

purpose: this virtual environment is used to isolate your environment when installing python modules. without this venv, you will install all python modules (can be identified as a long list in the requirements.txt file after you do the installation). with this venv, you basically install just the necessary modules. too many unnecessary modules might cause errors because Heroku will pull all the modules specified in requirements.txt(not recommended).

4. Enter virtual environment mode
source <your virtual environment name>/bin/activate

example,

source venv/bin/activate
5. Module installation

modules that you need to install:

  • whitenoise
  • django
  • gunicorn
pip install whitenoise
pip install gunicorn
pip freeze > requirements.txt

Then, check you new requirements.txt after you exit the virtual mode.

deactivate

you should see your requirements.txt containt modules similar to the following (version of each modules does not need to be exactly the same):

Django==1.11.10
gunicorn==19.7.1
pytz==2017.3
whitenoise==3.3.1

potential problems:

  • sometimes you might find more modules were being installed. try to deploy first without deleting the modules other than the modules written in the above instruction. if error occur, you can try delete the modules that were not part of the four modules above
6. create your runtime.txt (specifying Python runtime)

create a file runtime.txt and place your python version. Heroku will use this to identify the python version that must be used. for an updated documentation of which python version being supported by Heroku, check 'Heroku specifying Python Runtime document'

to check you python version,

python --version

for python 3 version,

python3 --version

edit runtime.txt and write the python version using the following format

python-3.5.2
7. Defining Procfile

if you have done the 'getting started on Heroku with Python' you should know this is an important part of Heroku and Django configuration

follow this step as it's not defined clearly in Heroku documentation at the time of this wiki was being written

create a file name Procfile. Make sure it's exactly the same (case sensitive).

vim Procfile

write the file exactly as follows

web: gunicorn <the name of your root folder>.wgsi --log-file -

for example (root folder is demo),

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

potential problem:

  • incorrect Procfile definition would result in a certain deployment failure
  • your .wsgi file was not directed correctly in settings.py
8. settings.py configuration

this will help you understand structure within the settings.py of Django configuration.

  1. DEBUG = true :

    Instruction: This wouldn't be a major issue since you're working on a demo for now so don't change this line after you created the django project.

    However, it's imperative that you understand this is where you set whether your code could be access from client side or not. it is recommended that you set it to false so that your code is not exposed to the public, compromising your app security. Some claimed that it had been an issue so for now you can set it to true. [This is still subjected to changes].

    Potential problems:

    • try leaving the default state did not work? try doing the opposite. if what you got was DEBUG = true, try switching it to false. and remember to take note of the changes you made.
  2. ALLOWED_HOSTS = []

    Django HTTP host header:

    This is where you define the domain and hosts for you to have access to the app. even when you're testing locally, you still need to define it as a string type. an example would be as follows,

    ALLOWED_HOSTS = [
      'time-map7-1.herokuapp.com',
      '127.0.0.1',
      'localhost'
      ]
    

    Potential problem that needs attention:

    • Host header poisoning security issue - issue raised in 2013 - (new members can ignore this part for now).
  3. INSTALLED_APPS[] :

    This is where you want to add the directory of where your static and template directories exist. you will need a directory of that are named static and template exactly. if you mistype this, the web server will not be able to find static and templates, which then it will throw errors.

    following the [directory structure](# MyProject-(root-folder) above, add the directory name in string format into the list

    'app'
    

    resulting,

    # Application definition
    
    INSTALLED_APPS = [
      'app',
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      ]
    

    More details: INSTALLED_APPS is directing to your application directory so that the web server can install your application. in this case, your application is a static web page that is in the app directory. As you can see there are other applications created by Django.

  4. MIDDLEWARE = []:

    whitenoise configuration:

    'whitenoise.middleware.WhiteNoiseMiddleware',
    

    example,

    MIDDLEWARE = [
      'django.middleware.security.SecurityMiddleware',
      'django.contrib.sessions.middleware.SessionMiddleware',
      'django.middleware.common.CommonMiddleware',
      'django.middleware.csrf.CsrfViewMiddleware',
      'django.contrib.auth.middleware.AuthenticationMiddleware',
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
      'whitenoise.middleware.WhiteNoiseMiddleware',
    ]
    
  5. Static files (CSS, Javascript, Images)

    make sure you have the following at the end of settings.py

    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/1.11/howto/static-files/
    STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join((BASE_DIR), 'static')
    

End of guide - Tips


This should be enough for you to start deploying a simple HTML page and CSS file. You can also refer back to two of the videos stated in the beginning of this guide.