TurnKey Linux Virtual Appliance Library

Django settings.py for development and production

So you developed a Django web application and now need to deploy it into production, but still need to actively continue development (bugfixes, tweaks, adding and testing new features, etc.)

In your development environment you probably had debugging enabled, performance settings disabled, used SQLite as your database, and other settings that make development easier and faster. 

But in production you need to disable debugging, enable performance, and use a real database such as MySQL or PostgreSQL, etc.

Hopefully, your development environment can simulate your production environment as well, sort of staging, so your final tests prior to deployment provides the smallest delta.

  • Sometimes you need to emulate the full production environment.
  • Sometimes you need to emulate the full development environment.
  • Sometimes a mixture of the two.

This leads to the question, how do you seamlessly manage your development and production settings without adding overhead?

It turns out there is quite a lot of discussion on how to setup Django settings.py that supports both a development and production environment, for example:

  • Completely different settings.py files (usually you configure the webserver to add the production settings to the python path, and use the default (development) settings when using the dev webserver.
  • By hostname
  • By variable (PRODUCTION = True)

We recently came across this issue when we were ready to deploy the TurnKey Hub into production.

I didn't really like the above mentioned solutions, so this is what I came up with:

  • settings.py (full settings for production)
  • settings-dev.py (override production for full development)

If the environment variable DEVELOPMENT is set, use settings-dev to override the production settings.

I was toying with the idea to have full control over the settings via the environment, for maximum flexibility, but in the end decided against it, as it added too much complexity with not enough gain.

Our settings_dev.py looks something like this:

DEBUG = True
TEMPLATE_DEBUG = True

COMPRESS_AUTO = True
SESSION_COOKIE_SECURE = False

DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = '/tmp/dev.db'
DATABASE_USER = ''
DATABASE_PASSWORD = ''

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
)
 
The settings.py (full settings for production) includes the following snippet at the end.
if os.environ.get('DEVELOPMENT', None):
    from settings_dev import *
 
You can get future posts delivered by email or good old-fashioned RSS.
TurnKey also has a presence on Google+, Twitter and Facebook.

Comments

The problem with that

The problem with that solution if I understand it correctly is that in the dev config file you don't have access to the already set settings so if you for example wan't to add an application to the installed_apps setting you need to add all of the ones that are in the production settings file.

If you instead write your settings.py (production) as normal and then in the settings_dev.py do from settings import * you can do things like:

INSTALLED_APPS += (
    'debug_toolbar',
)
 
Than all you have to do is make sure the dev server loads the dev config file.
Alon Swartz's picture

I've never need to do that

I've found debug_toolbar is really useful when optimizing my application, but is very annoying when doing regular development. Not only because the application is less responsive, but because it encourages premature optimization (which is the root of all evil).

So, for this edge case, I usually add debug_toolbar manually during the optimization phase.

With regards to your suggestion, it results in circular imports (though it should work) - for example:

foo.py
print "this is foo"
FOOBAR="foo"
from bar import *
print "this is foobar: %s" % FOOBAR

bar.py
from foo import *
print "this is bar"
FOOBAR="bar"

When we execute foo.py, this is what happens:

$ python foo.py
this is foo
this is foo
this is foobar: foo
this is bar
this is foobar: bar

No, there aren't any circular

No, there aren't any circular imports; I think Martin Lundberg is talking about doing it like this:

http://toastdriven.com/fresh/better-local-settings/

Fix:

git does this for me

normally as developer you use a version control system. so i use git and have a devel branch where new changes will be committed into. if the devel version seems to be stable i merge the devel branch into the productive and git handles the changes at the settings.py.

sometimes git displays some conflicts, but these are corrected quickly

Alon Swartz's picture

Using revision control is a must...

Using revision control is a must - I love git, I'm addicted, can't live without it.

But, I don't follow how you use git to achieve what the article is trying to explain:

In your development environment you probably had debugging enabled, performance settings disabled, used SQLite as your database, and other settings that make development easier and faster. 

But in production you need to disable debugging, enable performance, and use a real database such as MySQL or PostgreSQL, etc.

Do you update your settings.py file every time you need to fix a bug, tweak something, or add a new feature? This seems awfully repetitive and error prone...

try/except rather than if

I take a similar approach of an override at the bottom of the file but instead of checking an environment variable I try to import settings_dev 

try:
	from settings_dev import *
except ImportError, exp:
	pass

I have settings_dev.py ignored in source control but I do have a settings_dev.sample checked in for when I have other developers working with me.  

Nice and more

Alon,

Thanks for sharing.

I use similar approach. I have file called local_settings.py which is my development settings. local_settings.py is imported in settings.py Then I have bunch of other settings files - sandbox_settings.py, prod_settings.py etc. Where sandbox is my test environment, prod is production etc.

I use fabric to deploy my applications to different environments. File sandbox_settings.py is renamed to local_settings.py when I deploy to sandbox server.

Works for me.

Stack Overflow

This was discussed on StackOverflow, there's a few good tips there.

Lincoln Loop's django-startproject

I use Lincoln Loop's django-startproject. It includes a customized version of manage.py that looks for a "local" settings.py and loads that if it is present in the "conf/local" directory. Otherwise it falls back to loading the settings.py in the "conf" directory. The version of settings.py in "conf/local" can be complete unto itself, but more typically it imports the main settings.py from the "conf" directory and then overrides and/or extends those settings as necessary.

The settings.py in the "conf" directory should be version controlled, however the version in "conf/local" should not. (There is a subdirectory called "conf/local/example" and it iis a good place to put varioius examples of different useful local settings.py files and these can be version controlled.)

By the way, django-startproject extends this same concept to also support custom urls.py management. While not perfect, the only serious problem I have found with django-startproject is that experienced django programmers tend to grumble for a few days while they get used to it.

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account, used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <p> <span> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area> <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <tr> <td> <em> <b> <u> <i> <strong> <font> <del> <ins> <sub> <sup> <quote> <blockquote> <pre> <address> <code> <cite> <strike> <caption>

More information about formatting options

Leave this field empty. It's part of a security mechanism.
(Dear spammers: moderators are notified of all new posts. Spam is deleted immediately)