Better Local Settings
A common convention I've seen in the Django community is to place code like the following at the bottom of your settings file:
# ``settings.py``
# Lots of typical settings here.
# ... then ...
try:
from local_settings import *
except ImportError:
pass
Then storing machine/user-specific settings within a local_settings.py> file.
This file is set to be ignored by version control.
I can't argue with needing overridden settings (do it all the time) but that
import is backward in my opinion. My preferred technique is to still use the
settings.py and local_settings.py but relocate the import. So
local_settings.py starts out with:
# ``local_settings.py``
from settings import * # Properly namespaced as needed.
# Custom settings go here.
DATABASE_HOST = 'localhost'
The only other change is passing --settings=local_settings to any
./manage.py or django-admin.py calls.
Trivial implementation, you still only need to override what you need, no changes needed to version control or development workflow. And since you've already imported all of the base settings, you can reuse that information to create new settings, like:
# ``local_settings.py``
from settings import *
DATABASE_NAME = "%s_dev" % DATABASE_NAME
This is by no means a new technique, nor did I come up with it, but it's been
very useful to me and I have yet to encounter the drawbacks (other than
specifying the --settings flag, which also has an even easier fix via DJANGO_SETTINGS_MODULE) of this
approach.
Feedback, as always, is welcome.
Sorry, comments have been closed on this post.
10 Comments
I normaly use the standard settings as my default settings. This will make things a bit easier with manage.py etc. But I don't do a normal `from local_settings import *`. My code looks like this:
try:
from local_settings import *
if 'apply_settings' in globals():
apply_settings(globals())
except ImportError:
pass
This allows me to have a function in local_settings.py that changes the settings of the original file inplace. The `apply_settings` function in local_settings.py would look like:
def apply_settings(settings):
settings['DATABASE_NAME'] = "%s_dev" % settings['DATABASE_NAME']
Ok I admit, its a bit hacky ... but it skips the `--settings=local_settings` part.
# root settings conf. imports local settings and set DEBUG-related flags.
try:
from local_settings import *
except ImportError:
from default_settings import *
The first line of local_settings should be "from default_settings import *", then it can override those settings it sees fit.
I have used a very similar way described in this post for quite some time on a variety of different projects/servers, and it works great.
Instead of having a "local_settings.py" file I have a "settings_project.py" (which is included in VCS), and I then let the settings.py file hold the local settings, and exclude it from VCS.
Really simple, and I can access and override the project defaults as you show in your post, but without the need to specify --settings or DJANGO_SETTINGS_MODULE at all!
I just want to point out that this works in several levels if you wish. I have some projects that shares some settings, so I have different settings files on different "levels", and I can always override any setting in the local settings.py file.
The advantage of this approach is that all of my configs go in to source control, and I can run management commands for each environment just by changing in to that environments directory and using ./manage.py as normal. This has been working really well for me.
Then I saw Transifex' solution here: http://code.djangoproject.com/wiki/SplitSettings#UsingalistofconffilesTransifex
Now I use that, and I find it perfect: much more flexible, and solves the above problem: I can have a 99_derived.conf file that sets all my "derivative" settings, and have a 95_local.conf before it that does my local overrides and has access to all the settings defined previously.
project/settings/__init__.py # base config
project/settings/live.py
project/settings/testing.py
project/settings/dev.py
project/settings/local.py # excluded from vcs
Then using a bash script that uses an environment variable to switch to, it runs manage.py with an appropriate DJANGO_SETTINGS_MODULE. Works quite neatly.
execfile(os.path.join(PROJECT_PATH, "settings_local.py"))
That's all.
My code usually looks like this,
Keep up the good work