Taming Django settings.

settings.py roaringMy first introduction to Django was actually indirect, through Google App Engine. I was developing a back-end for my iOS scrapbooking app (yes, scrapbooking) Coolibah, and I wanted to build it once and never have to worry about it again. That was in 2009, and (for the most part) my vision worked. I didn’t have to worry about scalability, reliability, etc. The system ran without a hitch (except for a mandatory upgrade to a new datastore type in July of this year). But after six years, code rot has set in. Not in the server code, so much, as in the iOS application. It’s time for a complete rewrite, which also means a complete rewrite of the server code too.

So, I dusted off my Django install, updated everything, and created a skeleton project. One of the first orders of business in Django is configuring settings.py. This is where you set up your app’s database connection, extensions (called “apps” in Django parlance), middleware, templating, etc. What makes things a little more challenging is that the code will be executed in a few different types of environments. One (or more) developers will be running it on their local computer. There will (hopefully) be a staging server to test new features before promoting to production. And of course there will be a production environment. All with different database settings, debug settings, etc.

There are a few different approaches to dealing with this issue, but what I’ve found that works best is this approach:

  1. Place all common settings in the main settings.py file.
  2. Create separate settings files for each distinct environment:
    • settings_dev.py – development
    • settings_prod.py – production
    • settings_staging.py – staging
    • . . .
  3. Add this settings loader to the end of the main settings.py file:
# Add staging and production hosts below (e.g. {'prod.host.name':'prod'})

import platform
host = platform.node()
host_settings = 'settings_%s.py' % ((KNOWN_HOSTS[host] if host in KNOWN_HOSTS.keys() else 'dev'))
print 'loading %s for host %s' % (host_settings, host)

import os
execfile(os.path.join(os.path.dirname(os.path.abspath(__file__)), host_settings))

Now, when it’s time to deploy my app to the production server, I can add an entry to the KNOWN_HOSTS dictionary and load the correct settings file dynamically at run-time. Any unknown host is assumed to be a development box and will load the settings_dev.py file.