One-stop shop for configuring 12-factor Django apps
- Simple API for getting settings from environment variables.
- Supports wide variety of email, cache and database backends.
- Easily customisable and extensible.
- One line auto-config for many Heroku add-ons.
In your Django project's settings.py
:
import envsettings
SECRET_KEY = envsettings.get('DJANGO_SECRET_KEY', 'development_key_not_a_secret')
# Accepts the strings "True" and "False"
DEBUG = envsettings.get_bool('DJANGO_DEBUG', default=True)
FILE_UPLOAD_MAX_MEMORY_SIZE = envsettings.get_int('MAX_UPLOAD_SIZE', default=2621440)
Because of the way Django's email settings work, this requires a bit of a hack with
locals()
:
import envsettings
locals().update(
envsettings.email.get('MAIL_URL', default='file:///dev/stdout'))
This sets EMAIL_BACKEND
and whatever other values are needed to
configure the selected backend.
Standard SMTP backend:
# SMTP without TLS
smtp://username:password@host.example.com:25
# SMTP with TLS
smtps://username:password@host.example.com:587
Special Django backends for use in development:
# Console backend
file:///dev/stdout
# Dummy packend
file:///dev/null
# File-based backend
file:///path/to/output/dir
Proprietary backends (each requires the appropriate package installed):
# Requires `django-mailgun`
mailgun://api:api_key@my-sending-domain.com
# Requires `sendgrid-django`
sendgrid://username:password@sendgrid.com
# Requires `djrill`
mandrill://:api_key@mandrillapp.com
mandrill://subaccount_name:api_key@mandrillapp.com
# Requires `django-ses-backend`
ses://access_key_id:access_key@us-east-1
ses://access_key_id:access_key@email.eu-west-1.amazonaws.com
# Requires `django-postmark`
postmark://api:api_key@postmarkapp.com
Pass auto_config=True
like so:
locals().update(
envsettings.email.get(default='file:///dev/stdout', auto_config=True))
This will automatically detect and configure any of the following Heroku email add-ons: Mailgun, Sendgrid, Mandrill, Postmark.
So, for instance, you can configure your app to send email via Mailgun simply by running:
heroku addons:add mailgun:starter
By default it will use each provider's SMTP endpoint, however if it detects that the appropriate backend is installed (see list above) it will configure Django to use the HTTP endpoint which will be faster.
import envsettings
CACHES = {'default': envsettings.cache.get('CACHE_URL', 'locmem://')}
Django backends for use in development:
# Local memory
locmem://
# Local memory with prefix
locmem://some-prefix
# File based
file:///path/to/cache/directory
# Dummy cache
file:///dev/null
Redis (requires django-redis
package):
# Basic Redis configuration
redis://example.com:6379
# With password
redis://:secret@example.com:6379
# Specifying database number
redis://example.com:6379/3
# Using UNIX socket
redis:///path/to/socket
# Using UNIX socket with password and database number
redis://:secret@/path/to/socket:3
To use Memcached you need one of the following packages installed:
django_pylibmc
, django_bmemcached
, pylibmc
, mecached
Only django_pylibmc
and django_bmemcachd
support authentication and the memcached
binary protocol, so if you want to use either of these featues you'll need one of those
packages.
# Basic Memcached configuration
memcached://example.com:11211
# Multiple servers
memcached://example.com:11211,another.com:11211,onemore.com:11211
# With authentication
memcached://username:password@example.com
# Using the binary protocol
memcached-binary://example.com:11211
Pass auto_config=True
like so:
CACHES = {'default': envsettings.cache.get(default='locmen://', auto_config=True)}
This will automatically detect and configure any of the following Heroku cache add-ons: Memcachier, MemcachedCloud, RedisToGo, RedisCloud, OpenRedis, RedisGreen.
Django EnvSettings is designed to be easily extensible by subclassing one of the existing
settings providers: CacheSettings
, EmailSettings
, or DatabaseSettings
.
Obviously you can modify the configuration dictionary after it's returned from envsettings
.
However you can also set default values for each backend, while letting the environment determine
which backend to use. For example:
envsettings.database.CONFIG['postgres']['OPTIONS'] = {
'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE}
To add a new backend, subclass the appropriate settings class.
You will then need to add a key to the CONFIG
dictionary which maps
the URL scheme you want to use for your backend to the default config
for that backend. You will also need to add a method named
handle_<URL_SCHEME>_url
which will be passed the output from urlparse
and the
default config. The method should use the values from the parsed URL to update the
config appropriately.
For example:
import envsettings
class CacheSettings(envsettings.CacheSettings):
CONFIG = dict(envsettings.CacheSettings.CONFIG, **{
'my-proto': {'BACKEND': 'my_cache_backend.MyCacheBackend'}
})
def handle_my_proto_url(self, parsed_url, config):
config['HOST'] = parsed_url.hostname or 'localhost'
config['PORT'] = parsed_url.port or 9000
config['USERNAME'] = parsed_url.username
config['PASSWORD'] = parsed_url.password
return config
cachesettings = CacheSettings()
CACHES = {'default': cachesettings.get('CACHE_URL')}
To add a new auto-configuration provider, subclass the appropriate settings class and add a method
named auto_config_<PROVIDER_NAME>
. This will be passed a dictionary of environment
variables and should return either an appropriate configuration URL, or None.
The auto config methods are tried in lexical order, so if you want to force a method
to be tried first you could call it auto_config_00_my_provider
, or something like
that.
Here's an example:
import envsettings
class CacheSettings(envsettings.CacheSettings):
def auto_config_my_redis(self, env):
try:
host = env['MY_REDIS_HOST']
password = env['MY_REDIS_PASSWORD']
except KeyError:
return None
else:
return 'redis://:{password}@{host}'.format(
host=host, password=password)
cachesettings = CacheSettings()
CACHES = {'default': cachesettings.get('CACHE_URL', auto_config=True)}
Tested on Python 2.7, 3.3, 3.4 and PyPy, with Django versions 1.4 --- 1.7
Raise an issue on the GitHub project or feel free to nudge @_EvansD on Twitter.
MIT Licensed