Imran S.
Imran S.

Reputation: 935

How to use the same settings.py for staging and production. Django

I have many identical database instances

I want my Django settings to be able to chose any one of these with minimal efforts. I don't want to keep multiple setting files.

I know I can configure them like this but how to switch to anyone other than the default.

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'HOST': 'localhost'
  },
  'staging': {
    'ENGINE': 'django.db.backends.sqlite3',
    'HOST': 'staging.server.com'
  },
  'production': {
    'ENGINE': 'django.db.backends.sqlite3',
    'HOST': 'www.server.com'
  }
}

Upvotes: 0

Views: 2049

Answers (3)

Paulo Scardine
Paulo Scardine

Reputation: 77281

[update]

For config/code separation I'm using a project called django-decouple instead of rolling my own stuff, the rationale of the original answer remains valid.

[original answer]

I recommend using environment variables instead of if/elif chains and/or includes. The main reasons are:

  • config varies substantially across deploys, code does not - hence you should aim to strict separation of config from code.
  • environment specific information pertains to the environment - env vars are easy to change between deploys without changing any code.
  • avoids checking sensitive information like passwords into source control by accident.

For example:

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

Please read "the twelve factors app" for a longer explanation on the principles behind this practice and "stop writing settings files" for a practical approach to Django settings.

I also recommend using virtualenv. Some tips:

  • place my apps in a path like /opt/django-apps/project_name
  • install virtualenvwrapper and make a virtualenv with the same name of the project under some path like /var/lib/python-virtualenvs
  • issue a workon project_name when you want to work at the project

I use a wsgi.py like this:

import os
import site
import sys

APP_ROOT = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(APP_ROOT)
PROJECT_NAME = os.path.basename(APP_ROOT)
INSTANCE_NAME = os.path.basename(ROOT)
VENV = '/var/lib/python-virtualenvs/{}/'.format(INSTANCE_NAME)
# Add the site-packages of the chosen virtualenv to work with
site.addsitedir(VENV + 'lib/python2.7/site-packages')

# Add the app's directory to the PYTHONPATH
sys.path.append(ROOT)

# Activate your virtual env
activate_env=os.path.expanduser(VENV + "bin/activate_this.py")
execfile(activate_env, dict(__file__=activate_env))

os.environ.setdefault("DJANGO_SETTINGS_MODULE", PROJECT_NAME + ".settings")

from django.core.wsgi import get_wsgi_application
_application = get_wsgi_application()

def application(environ, start_response):
    os.environ['DEBUG'] = environ['DEBUG']
    os.environ['DB_NAME'] = environ['DB_NAME']
    os.environ['DB_PASS'] = environ['DB_PASS']
    os.environ['DB_HOST'] = environ['DB_HOST']
    os.environ['DB_USER'] = environ['DB_USER']
    return _application(environ, start_response)

Upvotes: 2

Imran S.
Imran S.

Reputation: 935

So I've been reading the book Two Scoops of Django and the whole chapter 5 is based upon this issue. This chapter, Settings and Requirement Files, answers all of my questions. This chapter is based upon Jacob Kaplan-Moss' The Best (and worst) of Django talk at OSCON 2011. See page 47 and onwards of the slide.

Basically, the idea is to use multiple settings files i.e., settings/base.py, settings/local.py, settings/production.py etc. And to use the proper one while launching the server using the --settings switch.

Upvotes: 0

Imran S.
Imran S.

Reputation: 935

I found a way but I am not sure if this is the proper way to do it. Please comment.

I have the main settings.py and the DATABASES setting in it look like...

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'HOST': 'www.server.com'
  }
}

And at the end of this file, I have the following code...

# Load the local overrides if there are any.
try:
    from settings_local import *
except ImportError, e:
    pass

Then I have a settings_local.py file in the same location, but ignored by Git, on my local environment as follows...

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'HOST': 'localhost'
  }
}

This allows my application to connect to the production database server if there is no settings_local.py file in the same directory as settings.py, and to the local (or staging) database if this file exists.

Upvotes: 0

Related Questions