How to manage local vs production settings in Django?
Two Scoops of Django: Best Practices for Django 1.5 suggests using version control for your settings files and storing the files in a separate directory:
project/ app1/ app2/ project/ __init__.py settings/ __init__.py base.py local.py production.py manage.py
The base.py
file contains common settings (such as MEDIA_ROOT or ADMIN), while local.py
and production.py
have site-specific settings:
In the base file settings/base.py
:
INSTALLED_APPS = ( # common apps...)
In the local development settings file settings/local.py
:
from project.settings.base import *DEBUG = TrueINSTALLED_APPS += ( 'debug_toolbar', # and other apps for local development)
In the file production settings file settings/production.py
:
from project.settings.base import *DEBUG = FalseINSTALLED_APPS += ( # other apps for production site)
Then when you run django, you add the --settings
option:
# Running django for local development$ ./manage.py runserver 0:8000 --settings=project.settings.local# Running django shell on the production site$ ./manage.py shell --settings=project.settings.production
The authors of the book have also put up a sample project layout template on Github.
In settings.py
:
try: from local_settings import *except ImportError as e: pass
You can override what needed in local_settings.py
; it should stay out of your version control then. But since you mention copying I'm guessing you use none ;)
Instead of settings.py
, use this layout:
.└── settings/ ├── __init__.py <= not versioned ├── common.py ├── dev.py └── prod.py
common.py
is where most of your configuration lives.
prod.py
imports everything from common, and overrides whatever it needs to override:
from __future__ import absolute_import # optional, but I like itfrom .common import *# Production overridesDEBUG = False#...
Similarly, dev.py
imports everything from common.py
and overrides whatever it needs to override.
Finally, __init__.py
is where you decide which settings to load, and it's also where you store secrets (therefore this file should not be versioned):
from __future__ import absolute_importfrom .prod import * # or .dev if you want dev##### DJANGO SECRETSSECRET_KEY = '(3gd6shenud@&57...'DATABASES['default']['PASSWORD'] = 'f9kGH...'##### OTHER SECRETSAWS_SECRET_ACCESS_KEY = "h50fH..."
What I like about this solution is:
- Everything is in your versioning system, except secrets
- Most configuration is in one place:
common.py
. - Prod-specific things go in
prod.py
, dev-specific things go indev.py
. It's simple. - You can override stuff from
common.py
inprod.py
ordev.py
, and you can override anything in__init__.py
. - It's straightforward python. No re-import hacks.