Django Settings

January 28, 2018

Django settings, like many Django features, are deceitfully simple. The Django boilerplate provides a settings file, you add some settings and you’re done. But to get the most out of your app you’ll need to spend a little more time getting things set up. If you’re new to Django this overview should help get your app started on the right foot. I’ll go over some of the basic variables your app will need. The important things to remember are to separate environments, remove all sensitive data, and don’t bloat the files.  

Separating environments means creating a new settings file for each environment. Assuming your local and production environments don’t share things like databases or 3rd party keys, we’ll need to tell Django where to look. To kick things off, you’ll want to create a base.py file that will hold all settings that are shared among every environment. This can hold most of the basic variables defined by Django when you set up your project. This is a good place to import your application packages and define your middleware, validators, etc. Next, I create local.py (or development.py) for my local environment.

It usually starts like this –

from .base import *

DEBUG = True

ALLOWED_HOSTS = [
    'localhost'
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

The first thing local.py does is import base.py. When we point Django at our local settings, we want the base settings as well. ALLOWED_HOSTS defines what domains are allowed to host the application. Locally I only need localhost. You can also see I have DATABASES defined. This makes it simple to use a different database locally if you can’t use your production database or aren’t ready to set it up. Note: I do not recommend using SQLite, even for development. Try to get your production database running locally. Bonus points if you put it in a Docker container.

Production and staging settings are likely very similar, so I’ll show an example production.py.

from .base import *

DEBUG = False

ALLOWED_HOSTS = [
    'calebfrancis.com'
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST'),
        'PORT': os.environ.get('DB_PORT'),
    }
}

For production, I’ve turned off DEBUG so users don’t get crazy Django error pages. I’ve also added the production domain to ALLOWED_HOSTS. The DATABASES variable looks pretty different. In this case, all of the important database data are stored as environment variables and pulled by Django when the app is loaded. This is what I meant earlier about removing sensitive data. Leaving production authentication in the repo is dangerous. Staging will have the exact same DATABASES code and you’ll set different environment variables set for that server. This is a good way of storing authentication for 3rd party APIs if you have a test version and a production version. Store the variables on the server, reference them in the app.

The last step is to point each server to the correct file. This again uses environment variables. Django automatically looks for DJANGO_SETTINGS_MODULE for its settings. Reference the file using dot notation, e.g. export DJANGO_SETTINGS_MODULE=settings.local for own machine.

Django settings are very minimal and easy to manipulate, so its easy to add bloat. It looks like a list of constants doesn’t it? Why not add a few more? Try to avoid this pattern. The settings files are for settings, not application code. While you can reference them in your app, try to keep actual data elsewhere. On that note, to access settings variables, add from django.conf import settings to the file you want use them in. Importing the file directly is possible, but using django.conf means you’ll always have the correct settings for that environment.

As for settings location, you can technically put them anywhere. I like to create a config directory and drop them in there. Just make sure you use the full path for your DJANGO_SETTINGS_MODULE variable.

myapp
- config
  - settings
    - base.py
    - local.py
    - production.py
    - staging.py

Once you start using this pattern it’ll feel more natural. Of course you’ll want to test it out and make sure it works for your application and adapt as necessary.