Django: Where does settings belong ?


Settings is very central to all Django applications. Django even barf if you
don't supply one and import any django modules or functions (most of it). The
way to specify settings to Django app however a bit awkward. Rather calling
some function and pass the settings to that function, Django require you to put
the path to settings module in os.environ dict. Consider a Flask application:-

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)

It feels natural. You instantiate an app, call it's run() method and pass
debug as parameter to the function. It's easy to explain. Or if Flask not
your favourite, let's take a look at Bottle example:-

from bottle import route, run
@route('/hello')
def hello():
return "Hello World!"
run(host='localhost', port=8080, debug=True)

It still maintain the same flow. But let's look at how we pass settings to
Django app. This is what you get in default manage.py generated by
django-admin.py startproject command:-

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')
if __name__ == '__main__':
from django.core.management import execute_from_command_line
execute_from_command_line()

Compared to example for other 2 frameworks, the logic now seem to branch into 2
separate paths. First you have to figure out what is going on with
os.environ.setdefault() stuff, and then the stuff with
execute_from_command_line(). Enough to confuse beginner. Only later on I
figured out that you can actually skip os.environ stuff and directly set
settings as you wish. The above example can be re-written as:-

from django.conf import settings
settings.configure(DEBUG=True)
if __name__ == '__main__':
from django.core.management import execute_from_command_line
execute_from_command_line()

Now it look more like the other 2 frameworks. This however not much an issue,
because once your application grow, you'll definitely want to put your settings
in one central place and could be the reason why Django has made that decision
for you early on. The real issue is where should we put the central settings ?

Django settings, being a pure python module mean it has to be somewhere on your
sys.path so Django can import it to initialize the application. Logically I
want the settings for myapp to appear as myapp.settings. This however would
make the settings now part of the application. But settings suppose to have
some piece of information that will be used to create and initialized the
application (ROOT_URLCONF come to mind) but now the settings itself already
part of the application. I've repeated the word application too much in last
sentence.

One situation when this chicken-and-egg manifest. I want to deploy my app using
setup.py which mean myapp will be installed in site-packages. That also
mean settings.py will also reside in site-packages. But for web application
there are more than just python code. There should be a directory to store
uploaded files or csv files for some external data. I want to keep all this in
a self contained project directory but since now myapp.settings reside in
site-packages I'm losing the ability to calculate the path to my project dir
at run time. While I can compensate this by having a standardized location on
production machine, I'd still want to keep this in one single project dir for
development so each developers work doesn't step into each other and also for
portabilty of development environment.

The only way now is to not installing myapp into site-packages but altering
sys.path to add path to the directory containing myapp package. Some of open
source django project I found put settings.py outside the app packages,
usually at the same level of manage.py or .wsgi script used to launch the
app. They then specify the settings as os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'. This make settings external to the application but at the same time
exposed settings into the global namespace. While I haven't yet found any
packages at PyPI using the name settings, it still doesn't feel right.

I take a look at how settings are handled in Pylons/Pyramid project. Few things
observed:-

  • They use INI files instead of pure python.
  • The INI files are placed at the top level of project directory.
  • Application get installed into site-packages using setup.py
  • Since settings stayed in project dir, you still get referenced to the project
    dir even your app get installed into site-packages.

While it look quite similar to placing settings.py at your project root, the
INI files is not python module so there's no problem of exposing the settings
into global namespace. The settings now also look truely external to the
application. This has getting quite long but still the question remained
unanswered, where should we put the settings file ?

Kamal Mustafa

CTO

Joined December 2010. Have been doing web development since early 2000 with classic ASP, then moved on to PHP and finally involved with Python/Django since joining Xoxzo Inc. During his spare time Kamal hacks various open source projects at github.