Skip to content

Instantly share code, notes, and snippets.

@drinks
Last active December 14, 2015 20:28
Show Gist options
  • Save drinks/5143901 to your computer and use it in GitHub Desktop.
Save drinks/5143901 to your computer and use it in GitHub Desktop.
Django local_settings made friendly with Foreman's .env file
##
# appname/management/commands/exportenv.py
#
import re
import json
import sys
import StringIO
from importlib import import_module
from optparse import make_option
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = '''Serializes individual settings items into json-safe
strings suitable for dumping into a .env for Foreman.'''
option_list = BaseCommand.option_list + (
make_option('--settings-module',
action='store',
dest='settings_module',
default='local_settings',
help='''The name of the local settings module to
export. Default is local_settings'''),
make_option('--outfile',
action='store',
dest='outfile',
default='.env',
help='''The name of the file to write. Set to None
to print to stdout. Default is .env'''),
make_option('--include-databases',
action='store_true',
dest='include_databases',
default=False,
help='''Whether or not to include the databases
dict in env output. Default is False.'''),
)
VALID_SETTING = re.compile(r'^[A-Z][A-Z0-9_]+$')
def handle(self, *args, **options):
flo = StringIO.StringIO()
failed_settings = []
local_settings = import_module(options.get('settings_module'))
settings_d = local_settings.__dict__
for setting, value in settings_d.iteritems():
if not self.VALID_SETTING.search(setting):
continue
# Skip databases if not flagged to include them
if setting == u"DATABASES" and not options.get('include_databases'):
continue
try:
flo.write(u"%s=%s\n" % (setting, json.dumps(value, default=self.__class__._datehandler)))
except Exception, e:
failed_settings.append("%s: %s" % (setting, e))
if options.get('outfile', 'None') != 'None':
with open(options.get('outfile'), 'w+') as fp:
fp.write(flo.getvalue())
else:
sys.stdout.write(flo.getvalue())
if len(failed_settings):
sys.stderr.write('\nFailed to parse some settings:\n')
sys.stderr.write('\n'.join(failed_settings))
flo.close()
@staticmethod
def _datehandler(obj):
if hasattr(obj, 'isoformat'):
return obj.isoformat()
else:
raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(obj), repr(obj))
# Add dj_database_url to your requirements.txt
import os
import re
import json
import sys
# All your non-local settings go here...
if 'DEBUG' in os.environ.keys():
# Load .env file and
# Parse database configuration from $DATABASE_URL
import dj_database_url
DATABASES = {}
DATABASES['default'] = dj_database_url.config()
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
for setting, value in os.environ.iteritems():
if re.search(r'^[A-Z][A-Z0-9_]+$', setting):
# Loading as json will fail if the value is a simple string
try:
setattr(sys.modules[__name__], setting, json.loads(value))
except:
setattr(sys.modules[__name__], setting, value)
else:
try:
from local_settings import *
except ImportError, e:
print """Caught %s trying to import local_settings. Please make sure
local_settings.py exists and is free of errors.
"""
raise
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment