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 intosite-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 ?