I’m going to talk here about various techniques regarding the Django’s settings.
Let’s assume the following project layout:
.
├── __init__.py
├── manage.py
├── settings
└── urls.py
How do I use custom settings or overwrite existing ones on my development machine ?
Answer 1
Create your custom settings file under the same parent as the existing settings.py. Let’s name the new file settings_local.py
At the bottom of settings.py, add the following:
try: from settings_local import * except ImportError: pass
Pros
- no need to change the manage.py or the wsgi file in order to apply the new settings
Cons
- hard/impossible to use different settings for different environment
Answer 2 (preferred)
Create a new directory called “settings” and move the existing setting file there. Then make a different file for each type of environment.
.
├── __init__.py
├── manage.py
├── settings
│ ├── __init__.py
│ ├── development.py
│ ├── production.py
│ └── settings.py
└── urls.py
settings.py will include the default Django settings, probably the file created by django-admin.py
development.py will hold settings/overwrites needed for the development environment.
The extra settings files (production.py, development.py, etc) will extend the existing settings.py (or another parent file which in turn extends settings.py) and add their own settings customizations.
This could be your development.py file:
from .production import * DEBUG = True TEMPLATE_DEBUG = True DJANGO_SERVE_PUBLIC = True PREPEND_WWW = False SEND_BROKEN_LINK_EMAILS = False # APP: debug_toolbar MIDDLEWARE_CLASSES += ( "debug_toolbar.middleware.DebugToolbarMiddleware", ) INSTALLED_APPS += ( "debug_toolbar", ) DEBUG_TOOLBAR_CONFIG = { 'INTERCEPT_REDIRECTS': False, } TEMPLATE_CONTEXT_PROCESSORS += [ 'django.core.context_processors.debug' ] Where production.py is:
from .settings import * import os.path PROJECT_ROOT = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../') DEBUG = False TEMPLATE_DEBUG = False
Once your settings setup is in place, all you have to do is change manage.py and your WSGI file.
The manage.py file could now look like this:
#!/usr/bin/env python from django.core.management import execute_manager import sys, os PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(0, PROJECT_ROOT) try: import settings.development # Assumed to be in the same directory. except ImportError, e: import sys sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things. You'll have to run django-admin.py, passing it your settings module. (If the file settings.py does indeed exist, it's causing an ImportError somehow.) " % __file__) sys.exit(1) if __name__ == "__main__": execute_manager(settings.development)
In the same time, your WSGI file would use settings.production:
os.environ[“DJANGO_SETTINGS_MODULE”] = “settings.production”
Pros
- easy to create settings for each of your environments (production, development, etc)
- it’s a great way to keep your settings organized, easy to find and edit.
- easier to reuse your settings for other projects. For example, we could use the same development.py file (as shown above) with other production.py settings.
Cons
- you have to change the manage.py and the WSGI file, which might not be possible on your client server.
Other Django settings tips
- do not use your project name in the settings, i.e. use ROOT_URLCONF = ‘urls’ and not ROOT_URLCONF = ‘myproject.urls’, use INSTALLED_APPS = (“appname”,) and not INSTALLED_APPS = (“myproject.appname”, ). You will then be able to easily move settings and applications between one project to another
- use calculated paths for TEMPLATE_DIR, MEDIA_ROOT, STATIC_ROOT etc, i.e. PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) and then MEDIA_ROOT = os.path.join(PROJECT_ROOT, “media”)
I seem to see “Answer 2″ more and more, where production and development settings configured in the settings/ directory. However, I’m curious as to what one should do with private settings that shouldn’t be committed to version control, such as passwords, api keys, and such.
How do you make this balance of having all variants of the settings, yet keep private data private – do you simply exclude the settings/development.py and settings/production.py from version control, or is there some other strategy? Just curious
As you mentioned, adding the private setting file to the versioning system ignore list will work fine.
Another solution is to place the private file outside the files which go under the versioning system.
One would have to extend the sys.path for the system to find that file.
There is also the possibility of storing the private settings in a database. Along with the setting name and encoded value there will be a public key and a host identification (unique) string (so one can find it’s own settings). Then each developer will use their own private keys to decode the settings.