I like Django. A lot.
But there's some things about it that bug me, particularly the settings module. The settings module, as you may or may not already know, is the central configuration file for your django project. It handles everything about your project, including: database host, login and password; email host (for emailing errors and whatnot), authentication; applications installed; etc... Well, you get the idea.
Fine, so what's the problem? Well, there isn't one. Unless you use version control like Subversion. And want to have separate environments for testing, staging, production. And the settings module that is version controlled specifies a production database and you need it to point to a test database for testing -- you know, like a real-life development environment!
There's a couple solutions to this dilemma: one involves leaving the settings module out of version control altogether and manually editing it in each environment you'll be running in. Or you could have it in source control and hack on it in each environment; then deal with merging changes, fixing conflicts, etc. after every update.
Or you can use the following approach that requires a little manual editing at the very bottom of your settings module:
# settings.py # Django settings for mccormac.org project. DEBUG = False TEMPLATE_DEBUG = DEBUG DATABASE_ENGINE = "postgresql" #... etc... # all the settings you want at default values # import local settings overriding the defaults try: from local_settings import * except ImportError: try: from mod_python import apache apache.log_error( "local_settings.py not set; using default settings", apache.APLOG_NOTICE ) except ImportError: import sys sys.stderr.write( "local_settings.py not set; using default settings\n" )
If you look at the example above, you can see we attempt to import from a module called local_settings; if we don't find it we log the issue and move on. This particular implementation attempts to use the apache log, but only works when running on apache.
Indeed, the mod_python module won't be available unless the settings module is actually running on apache, so you have to catch the exception otherwise the embedded webserver in development will crash on the line: from mod_python import apache.
Our local_settings module can now look like this:
# local_settings.py # Override default Django settings module # DEBUG = True DATABASE_ENGINE = "sqlite3" DATABASE_NAME = "/home/mike/test.db" TEMPLATE_DIRS = ( "/home/mike/dev/templates" )
With this configuration, the local_settings module doesn't even have to exist -- what I do is set default production values in the settings module and override necessary settings for staging and development in their corresponding local_settings module. Now you can add the main settings module to version control, create a 'svn:ignore' property for the local_settings module and you have a pretty flexible setup.

/blog/localized-settings-django/comments
I use a different approach: a settings (or _settings) folder in my django project, and a symlink from the right settings file to settings.py.
Each setup (prod/dev/test) has its own symlink that never changes, and all the different settings file are stored in svn. Thsi way you get an added bonus: different developers may have their own, specific settings file in svn, without cluttering the production one.
To deal with this I have all my settings in the settings.py file and then for each environment I have a settingsXXX.py The first line of that file is "from settings import *". Then whatever environment I am in I set the DJANGO_SETTINGS_MODULE to the settingsXXX.py file which inherits all the main settings and overrides the necessary ones with local values.
I do this not only for the differences in my Dev and Prod settings but I have settingsLaptop.py and settingsDesktop.py to deal with the differences there as well.
As for subversion the only file I check in is the root settings.py file.
I'm with Jay - that's how I do it too.
I basically tell apache which one to use, and then I can have multiple ones for testing, etc. Problem solved.
it's interesting to see the different approaches to the same problem.
jay - it looks like you've done the same thing but in an opposite manner :) i like the fact that you don't add any code to the "root settings.py file". on the other hand, i like all my "environments" to be configured the same, hence my approach.
At TrenchMice, we have three developers all doing the settingsXXX.py setup like Jay commented on - it's worked very well for us. Basically a local override. We complemented it a bit with a url file for each developer/environment as well.
I wrote up a bit about that setup on our blog - http://www.cogitooptimus.com/2007/03/...
I set an environment key, DEPLOYED, to "True" on my production server (in httpd.conf) then use
DEPLOYED = os.environ.has_key("DEPLOYED") and os.environ["DEPLOYED"] == "True"
Then I use conditional logic in settings.py to set things up how I need it. It works pretty well.
Michael, we have been using similar approach in other (eg. php) porojects as well - overriding the settings with local ones.
The only difference is that we do not keep production values in the default settings file, because we want to keep them secure.
With such approach we can easily give the whole project to contracted partners to let them run tests.
Just use ENV vars for everything in the settings module:
import os
DATABASE_NAME = os.environ['RCACHE_DB_NAME']
DATABASE_USER = os.environ['RCACHE_DB_USER']
DATABASE_PASSWORD = os.environ['RCACHE_DB_PASSWD']
this way you have a single settiings module, and everything just works on each server.
I use the ENV vars as well for a large chunk of the settings.py file. I find it's cleaner to have a single settings.py file. It keeps things unified when the environment dictates your settings file. Moving from production/dev/test setups require different user accounts but not different settings.py files.
I find it removes an element of human error and causes no surprises when you release new software or add new developers.
My 2cents
I stay with the symlinks, because I tend to use a lot of dumpdata's and loaddata's, and setting env vars for apache or changing the settings file for mod_python does not affect the command line.
It's a pretty simple approach. Keep a master settings file, and make a default symlink to it, so nothing breaks. For other environments, create env_settings.py and import the master file. Then change the symlink to point to the env file.
:)