Django Settings for Production and Development: Best Practices
When you’re just starting out with Django, it can be overwhelming to see there’s no standard approach to deal with settings. However, there are a few simple best practices that work when you start needing more than the basic settings file.
What’s the problem? Django stores all the settings in a project-wide settings.py file. All is fine until the moment you need different settings for different environments(such as a production environment and a development environment to start with).
Of the necessity to have different settings files
Your development settings should be different from your production settings. Why?
- you should protect sensitive things like database passwords, api secrets, private keys in a separate file
- the behavior of production code is not suited for development : for example you don’t want to send an email when you’re developing new features
Here are a few things that may change from one environment to another:
- database details: database name, user name and password
- api keys
- your own private keys for encrypting data
- debug variables (DEBUG and TEMPLATE_DEBUG)
- path to different tools needed by your Django applications
- and any other flags needed to make your application work differently in development and in production
We’re going to compare three different ways to organize your settings when having one setting file doesn’t cut it anymore.
First solution: local settings
This solution relies on having one settings.py file with common settings and a local_settings file where you define environment-specific settings.
Let’s see:
### settings that are not environment dependent
try:
from local_settings import *
except ImportError:
pass
### environment-specific settings
### example with a development environment
DEBUG = True
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django',
'USER': 'django',
'PASSWORD': '1234',
'HOST': '',
'PORT': '',
}
- Advantages: simple if you only need a development and a production environment (no staging) – the local_settings.py should stay out of source control and you need to have a separate one for development and production.
- Disadvantages: it limits what you can do with settings such as modify common settings in the local_settings for example. It can work for the most simple case though.
Second solution: environment-based settings
This is one from Ches Martin. It relies on having an environment variable pointing to the right python module. It has the advantage of being explicit, so you can name your specific settings files explicity (production file being production.py for example).
__init__.py
defaults.py
dev.py
staging.py
production.py
What happens when we do import settings? Settings is in this case a package (a package in Python being a directory with an __init__.py file inside), so when the interpreter loads the package it executes __init__.py.
By default, let’s make it work in development environment.
from dev import *
### sensible choices for default settings
from defaults import *
DEBUG = True
### other development-specific stuff
from defaults import *
DEBUG = False
### other production-specific stuff
How to use it in production and staging environments?
The trick is that the settings module location can be overriden by settings an environment Django variable. So we need to override that variable before starting our webserver. For example if you use Apache as your Django web server, modify your Apache configuration file with:
Third solution: system-wide settings
import os
ENVIRONMENT_SETTING_FILE = '/etc/django.myproject.settings'
### this will load all environment file settings in here
execfile(ENVIRONMENT_SETTING_FILE)
### all common settings
### ...
We can see one problem of doing it this way is that we cannot modify variables defined in the common settings.py file in the environment-specific files.
On the other hand, it simplifies the management of environment-specific settings files. Create a file for development, staging and production, secure it with some tight permissions, and forget about it.
To conclude
There are other ways to manage your settings, so you can experiment a little bit. Check the list of resources to know more about managing your settings. And drop a comment here if you want to share the way you’re doing it!
Resources:
- Splitting up the settings file, very comprehensive resource from the official Django website
- Django settings, again from the official Django website
- Extending Django settings for the real world from Yipit
- Django settings at Disqus: for a more complex and modular settings configutation.
- Stack Overflow:
- Django SnippetsĀ Keep settings.py in version control safely

Hey Tommy,
An alternative way, possibly more centralized, in the sense that you don’t need to maintain separate files, is the following:
- Keep all configuration parameters in the buildout script.
- Keep the settings.py as a template file, that sets its template parameters according to the values of the config parameters in the buildout.
- On build, parse the template using recipe collective.recipe.template, and output it in your project folder.
Voila!
No separate settings files to maintain. Just a centralized configuration file, which builds the settings file. You only tweak the template, and the buildout script, and the rest appears automagically!
Full local_settings:
imort os
PROJECT_DIR = os.path.dirname(os.path.dirname(__file__))
try:
execfile(os.path.join(PROJECT_DIR, “local_settings.py”), globals(), locals())
except IOError:
pass
So, in your local_settings.py you can change any var.
@Pambo, that is, if you use buildout
Never used it yet. Thanks for the alternative dude
that’s a good one, thanks Luciano!
Another pattern that can be useful with the first approach when you want to modify existing settings instead of using either/or default/overridden value for a given setting, adding a bit of flexibility to that approach.
from environment import *
if ‘EXTRA_INSTALLED_APPS’ in locals():
INSTALLED_APPS += EXTRA_INSTALLED_APPS
I like to invert your option #1. I have a settings_common.py that has a bunch of shared configuration, and some sane defaults. I also have a settings.template file that is in source control and imports settings_common. The advantage is that you can then modify settings bit by bit, such as adding additional apps to particular deployments. Here is a gist that shows what I mean: https://gist.github.com/1996312
@tommy: How do you handle deployments? Fabric?
@Pambo yup. Fabric. It’s pretty awesome actually, might write a blog post about it one of these days
@tommy: Can’t wait for it
@Pambo: we tried approach with buildout variables and templated settings.py in our application and found that it’s not really convenient. It worked OK until we weren’t concerned about running full continuous delivery pipeline. However shortly after starting building such pipeline we found that templating makes very difficult to follow “Single Build Artifact” approach that’s, in my opinion, is really worth to have in your workflow.
After some research and considerations we started to use plain key=value files for each environment (similar to option 2 in the article) and never looked back. Django settings.py loads and parses corresponding file, Jenkins CI can use it too and special wrapper for supervisord pushes all values from this file into environmental variables so they can be used from any other non-Python process that started by supervisord.
Really happy with this setup so far.