Better environment configuration, inspired by Heroku, borrowed from Foreman.
The twelve-factor application pattern, published by one of Heroku’s co-founders, define a methodology for developing and deploying web applications, specifically software-as-a-service.
These are the twelve in brief. More detail is available on the website.
If you’ve used Heroku then you’re probably quite familiar with these factors as constraints. The biggest difference approaching Heroku deployment with traditional Django development is that, uh, there’s no way you can adequately track configuration values like database credentials in your settings, and you sure as hell can’t resort to a local_settings file. And that’s not a bad thing.
In the twelve-factor model, all configuraiton variables are stored in the OS environment. This makes updating settings in the deployed application way easier but what to do in local development?
The first solution is to use Foreman, a Ruby application that manages
Procfile based processes. Your Procfile is just a template of process
commands and it’s what
Heroku uses to identify what needs to run in your app. The local
environment variable issue is solved by including a .env
file in your
project directory (excluded from version control) into which you can
declare your own local configuration settings.
The upside is that everytime you run foreman start
or foreman run
python manage.py migrate
you’re reading in those variables. The
downside is that for running management commands it adds a few extra
keystrokes. Not to mention that you lose the devserver’s reload on code
change capability. Nobody wants to stop and start and stop and start
processes manually.
So let’s just update the Django project’s manage.py file. What we want
to do is read the faux environment variables into Python’s os.environ
dictionary. Here we’ll take a cue, and some code, from Honcho.
Honcho is a Python port of
Foreman written by Nick Stenning and
distributed using the MIT license. All that we want to accomplish is
getting configuration values from our own .env
file.
Here’s the default Django manage.py file:
The updated manage.py code just lifts Nick’s read_env
function and
executes it whenever a command is issued using the manage.py file.
Of course if you’re using Honcho then you could simplify your manage.py file by simply importing the function.
The next step is to add these values to your .env
file and then update
your settings file to get them. Here’s a small sample .env
file:
And in your settings file, instead of:
Update to this:
(Thanks to @emperorcezar for pointing this in a more concise direction)
False is a more sensible default to avoid accidentally exposing debug
data. The new settings code calls a small helper function bool
because
the value returned will be a string saying ‘True’ or ‘False’ and we want
to work with boolean values. Any place you have a setting that might
change between environments, just ensure that the value is set by a
default value after checking the os.environ
dictionary.
It’s very important to be able to handle default values for your settings, and to provide sensible defaults. In the example above we shared a tiny helper method that picks out boolean settings from the environment. In practice, we’ve found it simpler to accommodate non-Boolean values, too, in the settings helper function.
Now you can replace any environmentally configured setting type.