2👍
You could set a environment variable to specify which settings file to use, and then in yourmanage.py
and wsgi.py
, do something like this
config_mode = os.getenv('DJANGO_CONFIG_MODE', 'base')
config_dict = {
'base': 'settings.base'
'local': 'settings.local'
'production': 'settings.production'
}
os.environ.setdefault('DJANGO_SETTINGS_MODULE', config_dict[config_mode])
# or if you prefer not using a dictionary or if-else blocks, you could
# set the settings file name you wish to use as the DJANGO_CONFIG_MODE environment
# variable and use that directly
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.{0}'.format(config_mode))
You might also want to specify the mode in your different settings files, so that your code can behave differently in different modes.
CONFIG_MODE = 'base' # or 'local' or 'production'
in your various settings files, and use it in your code base as required.
4👍
The DJANGO_CONFIGURATION
variable refers to a configurations.Configuration
subclass. As described in the docs on usage patterns, the idea is to trade in the tedious overhead of maintaining multiple settings files for a much DRYer Mixin/Class workflow scheme. I know it’s annoying having to go change manage.py
and wsgi.py
, but you get a lot for it.
# example settings.py
from configurations import Configuration, values
# Build up some mixin classes for related or app-specific settings:
class AppsMixin(object):
DJANGO_APPS = (
'django.contrib.auth', 'django.contrib.contenttypes',
'django.contrib.sessions', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.sites',
'django.contrib.flatpages', 'django.contrib.sitemaps',
'django_extensions'
)
ADMIN_APPS = ('filebrowser', 'grappelli', 'django.contrib.admin',)
DEV_APPS = ('django.contrib.admindocs', 'debug_toolbar',)
DEFAULT_APPS = (
'tagging', 'imagekit',
'tinymce', 'ajax_select',
'crispy_forms', #...
)
@property
def INSTALLED_APPS(self):
""" Control application ordering dynamically """
OUT_APPS = self.DJANGO_APPS + self.ADMIN_APPS
if self.DEBUG:
OUT_APPS += self.DEV_APPS
return OUT_APPS + self.DEFAULT_APPS
class AuthURLMixin(object):
LOGIN_REDIRECT_URL = 'site-login-success'
LOGIN_URL = '/auth/login/'
LOGOUT_URL = '/auth/logout/'
class CrispyFormsMixin(object):
""" django-crispy-forms specific settings """
CRISPY_TEMPLATE_PACK = 'bootstrap3'
@property
def CRISPY_FAIL_SILENTLY(self):
return not self.DEBUG
class Base(AppsMixin, AuthURLMixin, CrispyFormsMixin, Configuration):
""" Your equivalent for settings/base.py """
pass
class Local(Base):
""" ~ settings/local.py """
DEBUG = True
TEMPLATE_DEBUG = DEBUG
# Custom setting that lets subclasses or your apps
# check which subclass is active.
STAGING = False
# Enable a setting to be defined in os.environ, with a sensible default
# Don't forget the 'DJANGO_' prefix (e.g. DJANGO_TIME_ZONE)
TIME_ZONE = values.Value('America/New_York')
HTTPS_ONLY = False
# Stash the secret key in os.environ as DJANGO_SECRET_KEY
SECRET_KEY = values.SecretValue()
@property
def CSRF_COOKIE_SECURE(self):
""" chained dynamic setting """
return self.HTTPS_ONLY
@property
def SESSION_COOKIE_SECURE(self):
""" chained dynamic setting """
return self.HTTPS_ONLY
class Staging(Local):
""" This class is used for testing before going production """
STAGING = True
TIME_ZONE = values.Value('America/Phoenix')
#...
class Prod(Staging):
""" ~ settings/production.py """
DEBUG = False
STAGING = False
HTTPS_ONLY = True
Then, from your laptop:
/path/to/project/$ python manage.py shell --configuration=Local
>>>from django.conf import settings
>>>settings.DEBUG, settings.STAGING, settings.TIME_ZONE
(True, False, 'America/New_York')
From your remote server:
/path/to/remote/project/$ python manage.py shell --configuration=Staging
>>>from django.conf import settings
>>>settings.DEBUG, settings.STAGING, settings.TIME_ZONE
(True, True, 'America/Phoenix')
Once everything is perfect, go system-wide:
# /etc/environment
DJANGO_SETTINGS_MODULE=thisproject.settings
DJANGO_CONFIGURATION=Prod
Now the three-file problem has been solved with a few extras:
- The dynamic properties allow you to toggle or interpolate any number
of related settings at once through instance methods. - Chunks of settings can be introduced and removed through the mixins.
- Sensitive key settings are kept out of source control.
So, you could conceivably make three of these files with three classes each but why not just make one with nine?
0👍
You could try using an single settings file and setting up conditions inside it. So when you run it locally it sets different parameters than when you run it remotely. For example:
import os
DEVELOPMENT_MODE = not os.path.isfile('/mnt/SERVER')
DEBUG = DEVELOPMENT_MODE
TEMPLATE_DEBUG = DEBUG
The above checks for a file on the machine ‘/mnt/SERVER’, my server has this file, my laptop does not. Its an empty file, just a place holder. But it sets a flag in my settings that I can use as such:
if DEVELOPMENT_MODE:
CONST_URL = 'http://localhost:8000'
else:
CONST_URL = 'http://www.website.com'
I’ve been using this for years, the advantage is my apache, wsgi, and manage.py remain untouched.