简体   繁体   中英

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

I have many identical database instances

  • localhost
  • staging.server.com
  • www.server.com

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'
  }
}

[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)

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.

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 ie, settings/base.py, settings/local.py, settings/production.py etc. And to use the proper one while launching the server using the --settings switch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM