Django Best Practice: Settings file for multiple environments

When developing a django application you must have solved the problem of managing separate configuration for different environments like development, testing, staging, production etc. I was using django from v0.96, Django doesn’t have any standard approach to handle multiple settings. When I am starting new django project , I want to make sure my application should,

  • Allow me to manage any number of environments without any hassle.
  • Secure all sensitive data, don’t track them in version system.
  • Avoid duplicate code by keeping common settings.
  • Support one click test & deploy to any environments

There are several ways to meet above requirements, however my favorite one is having settings module.

Create Settings module

Once you create django project, remove settings.py and create a folder called settings, here you can maintain enviroment specific files, so your project structure will be look like this,

mysite/
├── manage.py
└── mysite
  ├── __init__.py
  ├── settings
  │ ├── __init__.py
  │ ├── base.py
  │ ├── local.py
  │ ├── production.py
  │ ├── staging.py
  │ └── testing.py
  ├── urls.py
  └── wsgi.py

base.py will contain all of our common settings between all environments, import this file to all other environment file, e.g.: local.py will look like

from .base import *
INSTALLED_APPS += (
'debug_toolbar',
)

As we have settings file for each environment, we can easily manage environment specific settings into respective files.

Read configuration from json file

Many developers recommends read from environment variable, but I always have multiple projects in my system and it may conflict.I prefer read from configuration file like xml, config , yaml or json. I chosen json because it can be used for non-python application as well. Create json file mysite_config.json like

{
"SECRET_KEY" : "My secret key here",
"DATABASE_URL" : "postgres://user:pwd@localhost:5432/mysitedb",
"DEBUG" : "True"
}

The mysite_config.json file should be untracked from the version control system(you can track local config file for team collaboration), set file location in environment variable as,

export MYSITE_CONFIG="/Users/shabeer/.configs/mysite_config.json"

you can set configuration in base.py using below code

import os
import json
from django.core.exceptions import ImproperlyConfigured
with open(os.environ.get('MYSITE_CONFIG')) as f:
configs = json.loads(f.read())
def get_env_var(setting, configs=configs):
try:
val = configs[setting]
if val == 'True':
val = True
elif val == 'False':
val = False
return val
except KeyError:
error_msg = "ImproperlyConfigured: Set {0} environment variable".format(setting)
raise ImproperlyConfigured(error_msg)
#get secret key
SECRET_KEY = get_env_var("SECRET_KEY")

Execute management command

As we are not using django default settings module, it is important to specify settings file while executing any management module (runserver , syncdb etc),

python manage.py runserver --settings=mysite.settings.local

OR you can set DJANGO_SETTINGS_MODULE as environment variable

export DJANGO_SETTINGS_MODULE=mysite.settings.local

Now you can manage any enviroments, all your application code will tracked in version control, only thing you need mange is to create configuration file(e.g.:mysite_config.json) for each environment.

You can use similar approach for your package management file requirements.txt.

This working model for my projects, if anyone encounter a problem with this approach, we can discuss the same and update it.