DAMON BLOGONS

The Perfect Django Settings File

October 15, 2009 · 13 Comments

my-django-ponyI’ve been developing Django applications for quite some time now, and I’ve amassed a few tricks. Here’s an example of a settings file I’ve created for a recent project. I’ll explain all of the bells and whistles below.

Here’s the whole file: http://gist.github.com/214361

The rest is after da jump!


Debug Switch
Using this bit of pre in place of plane old DEBUG=True will allow you to have your Django project automatically switch out of debug mode when on the production server. Sometimes I’ll add several sites to the if statement so that on testing servers, QA testers don’t get confused.

# Set DEBUG = True if on the production server
if socket.gethostname() == 'your.domain.com':
    DEBUG = False
else:
    DEBUG = True

Database Settings
I always leave the database bit blank so you are forced to include a “local_settings.py” (talked more about below). I like to run a sqlite database on my localhost, and a postgresql or mysql database on my production server. This way, you don’t have to worry about ignoring your “settings.py” file in your repository updates. Just have your repository ignore “local_settings.py”.

# The database settings are left blank so to force the use of local_settings.py below
DATABASE_ENGINE = ''
DATABASE_NAME = ''
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''

Media Root
This line will automatically build a variable which stores the path to this file (your settings). I always store my media in a directory called media within the project. Using this, your media directory is built dynamically so you don’t have to fiddle with your settings each time you go production. This also goes for any other directories you want to include.

PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')

Context Processors
These guys can get annoying sometimes. If you don’t write your context processors into your settings, they’re going to default and leave out things like the request (depending on which version of Django you have I believe).

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.core.context_processors.auth',
    'django.core.context_processors.media',
    'django.core.context_processors.request',
)

Using Debug Switches
I’ll probably get yelled at for putting this in, but to keep things neat, I like to only include what’s necessary in my context processors. Here you’ll see that the debug processor is only turned on if the server is not production. Same for the i18n processor, but with the i18n switch. More about the “debug toolbar” later.

if DEBUG:
    TEMPLATE_CONTEXT_PROCESSORS += ('django.core.context_processors.debug',)
if USE_I18N:
    TEMPLATE_CONTEXT_PROCESSORS += ('django.core.context_processors.i18n',)
if DEBUG:
    MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)

Template Directories
I like to put my template directories within their respective application directories. So using this looping method of peeking in each app directory for a templates directory will automatically add any dir called “templates” within your project dir to the templates tuple.

# Dir Structure
# + Application
#  + templates
#   + Application
#    - someTemplate.html
#  - models.py
#  - views.py
#  - otherAppSpecificFiles.py
# + OtherApplication
# + Templates
#  - base.html
# - settings.py
# - urls.py
# - otherfiles.py

TEMPLATE_DIRS = ()
for root, dirs, files in os.walk(PROJECT_PATH)
    if 'templates' in dirs: TEMPLATE_DIRS += (os.path.join(root, 'templates'),)

Must Have Django Applications
Below are some must have Django applications. I’ll list those in a sec, but one very important issue is displayed here as well. The time has come to STOP using mod_python to deliver your applications!!! Everyone should be aboard with wsgi these days, and wsgi has a neat ability. WSGI is able to dynamically load the applications appending the current directory to your Python path. What’s sweet about this is that you don’t have to have “myproject.application” anymore. You can just write “application”. This gives your project more portability! Portability = Rad so this is a good thing.

Must Have Appz:

  • Django Extensions: This application gives you a ton of great stuff for your Django app including runserver_plus, shell_plus, and a bunch of other things. runserver_plus gives you the ability to have a shell in browser with the current context if debug is turned on. How awesome! Theres a lot of other bells and whistles in django-extensions which you can read about here.
  • SORL: This application allows you to use a template tag or model field to dynamically create thumbnail images. It will automatically resize and crop images (including TIF files, PDFs, PNGs, etc…). One thing with PNGs is that it won’t obey alpha transparency. For PNG alpha transparency layers, check this fix out.
  • Filebrowser: This sweet app puts a filebrowser into the django admin which you can then use in TinyMCE or another rich text editor.
  • Chunks: This app allows you to have a template tag with which you can define keys for short (or long) text chunks in your templates. Then in your django admin, you can define these keys, and have an instant place in the CMS to update these text chunks. Neat right?
  • Registration: This baby takes care of all of your registration needs. It uses django’s built in auth backend, but has all of the views and urls written so that your applications user registration is practically plug and play. Now all you have to do is define the templates.
INSTALLED_APPS = (
    # ...
    # Third Party Django Applications
    'django_extensions',
    'sorl.thumbnail',
    'filebrowser',
    'chunks',
    'registration',

    # Project Applications
    'app_name',
)

Template Tags
This guy is pretty important. The DRY principle states very plainly, “don’t repeat yourself”. Seriously, stop repeating yourself. I pump all of my template tags into this tuple here, and then in a bootstrap.py (could be your __init__.py, doesn’t matter) I loop through an add these template tags to my built ins. Here’s a snippet with that code if you want to read up more on that. This allows me to just use my favorite template tags within templates without having to load them at the top of each template.

TEMPLATE_TAGS = (
    'sorl.thumbnail.templatetags.thumbnail',
    'chunks.templatetags.chunks',
)

Local Settings
Finally, this is at the bottom of each of my settings.py files. This ensures that I’m using the local_settings.py file for all of my local resolution settings respective to that machine. So for instance, in production, I may be using a mySQL database, whereas on my local machine, I prefer to use a sqlite file.

try:
    from local_settings import *
except ImportError:
    pass

Once again, here’s the whole file: http://gist.github.com/214361

If you have any questions, or suggestions on how to make this file better, please post them in the comments! Thank you!

Update: Switched snippet links from dpaste to git hub so that they’re archived.

Categories: Python
Tagged: , ,

13 responses so far ↓

  • Aaron // October 16, 2009 at 1:45 am | Reply

    Sounds awesome!

  • Sumit Chachra // October 16, 2009 at 1:56 am | Reply

    I prefer to use bash variables to identify prod/dev/qa etc. and then read them off in the settings.py and have big if/else blocks for environment specific settings. Rest is common.

    • Damon Jablons // October 16, 2009 at 9:19 am | Reply

      That sounds like a good idea, do you have an example of how it’d look? I’m assuming you’d have to input your variables with the runserver command.

      • Sumit Chachra // October 16, 2009 at 3:27 pm | Reply

        No… nothing to give runserver. Use os.environ to get the values and then some if/else blocks works just fine:

        ENV = os.environ['ENV']

        if ENV == ‘dev’:
        IS_DEV = True
        DEBUG = True
        LOG_LEVEL = logging.DEBUG
        .
        .
        .
        .

  • David Wolever // October 16, 2009 at 2:08 am | Reply

    Ah, very nice. Thanks!

    You’ve touched on it, but I like to create a ‘path’ function:
    import os
    ROOT = os.path.abspath(os.path.dirname(__file__))
    # get paths relative to settings.py
    path = lambda x: os.path.join(ROOT, x)
    Which I can then use all over the place:
    DATABASE_NAME=path(‘db.sqlite3′)
    TEMPLATE_DIRS=path(‘templates/’)
    … etc …

  • David // October 16, 2009 at 4:00 am | Reply

    Hi,
    I have a few suggestions, but first of all I want to say that I like your approach, it’s much better than many others I’ve seen on the past.

    1. I’m pretty sure django does the same as your “Template Directories” trick on the fly for you already.

    2. I don’t think it’s a good idea make your repository ignore local_settings.py, I’d rather put it on the Python path somewhere else.

    That’s all :)

    • Damon Jablons // October 16, 2009 at 11:02 am | Reply

      Hey David,

      I’m interested in why you suggest that. All that my local_settings.py file has is some DB settings. It doesn’t need to be version controlled. It only consists of four lines.

      :D

  • How to serve media with Django’s runserver and only with runserver « DAMON BLOGONS // October 16, 2009 at 11:35 am | Reply

    [...] But I’m the type of guy who has forgotten to change DEBUG to false on the production server (I know I know!! This is the reason I do this). [...]

  • Jon Gales // October 16, 2009 at 2:01 pm | Reply

    There are some good tips here, but I noticed your links to Google Code are all messed up. I’m not quite sure how, but it looks like WordPress switched code.google.com to be pre.google.com (I’m guessing something with the code and pre HTML tags).

    Also, for template directories you don’t need to specify these out if you name them like you do. Django automatically looks for a directory called templates in all installed apps. Check out django.template.loaders.app_directories.load_template_source in the docs http://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types

  • Spaizkadett // October 19, 2009 at 7:50 am | Reply

    To get it to work on a windows box add:

    .replace(‘\\’,'/’)

    to all the settings that has anything with a path in it

  • Brainfuck Python Interpreter « Abd Allah Diab’s Blog // October 19, 2009 at 6:31 pm | Reply

    [...] discovered the language while I was reading an article about writing the perfect settings file for Django. The author used DPaste website to link to pieces of code. DPaste website says that it uses [...]

  • uberVU - social comments // October 20, 2009 at 10:36 pm | Reply

    Social comments and analytics for this post…

    This post was mentioned on Reddit by arnar: No I mean having it in debug mode by default, disabling it only for production hostnames, sounds dangerous. Typo in hostname, or some change of configuration and you might be exposing sensitive stuff to the w…

  • Brainfuck Python Interpreter « Abd Allah Diab's Blog // January 9, 2010 at 6:26 am | Reply

    [...] discovered the language while I was reading an article about writing the perfect settings file for Django. The author used DPaste website to link to pieces of code. DPaste website says that it uses [...]

Leave a Comment