3

I have been wondering about this for awhile. Namely, how does one go about isolating the config from the codebase when doing projects in Python and/or Django.

In particular, these thoughts have been inspired by one of Heroku's 12 Factors: III Config

What are some ways one could do this? How could he comply with this requirement when writing projects in Python, especially Django?

MadPhysicist
  • 5,401
  • 11
  • 42
  • 107

1 Answers1

4

Using Environment Variables

The most common way to solve this problem is to use environment variables.

For example in a Django app's settings.py you could write the following:

import os
if os.getenv("DJANGO_DEBUG") == '1':
    DEBUG = True

API keys would also be very similar:

import os
API_KEY = os.getenv("API_KEY", None)

Another way of doing this using the django-environ package was suggested by FlipperPA. It was inspired by 12factor, so it seems like a perfect match for this question.

If you deploy using Heroku then you can write your own environment variables for each dyno under settings. If you use another deployment method like AWS CodeDeploy you can write a shell script to set the environment variables by retrieving them from a secure store (like AWS Paramater Store)

Setting Environment Variables

To set these environment variables depends on your Operating System. Environment variables are also inherited from your command line, so for Linux you would have to add the environment variable to your run scripts and on Windows you can add a system variable.

Windows system environment variable (Universally accessible environment variable):

setx API_KEY abcdefghijklmnopqrstuvwxyz123

Windows temporary environment variable (All processes invoked after running this command can access the variable):

set API_KEY abcdefghijklmnopqrstuvwxyz123

Adding a environment variable for all processes in Linux is more complicated, follow this answer to make an environment variable automatically set when a shell starts.

Linux temporary environment variable (All processes invoked after running this command can access the variable):

export API_KEY="abcdefghijklmnopqrstuvwxyz123"

Testing Environment Variables

To test the environment variables set you can use the following command (Replace "API_KEY" with whatever the name of the variable is):

Windows:

echo %API_KEY%

Linux:

echo $API_KEY

If theses return the same thing you entered it should be working. You can try it out in python by typing:

python

You should then see something like the following:

Python 3.6.2 (default, Jul 17 2017, 16:44:45)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 

You can then write your python to test it out:

import os
os.getenv("API_KEY")

And you should see the value of your environment variable printed out.

  • 1
    How do you set these environment variables? – MadPhysicist Jul 22 '17 at 09:46
  • Are these the OS variables or virtualenv variables? – MadPhysicist Jul 22 '17 at 09:46
  • 1
    I've edited my original answer to show you how to set and test environment variables. These work with Virtualenv but you can look at [this](https://stackoverflow.com/questions/9554087/setting-an-environment-variable-in-virtualenv) thread to set environment variables only when your virtualenv is loaded. – Phillip Cutter Jul 22 '17 at 23:39
  • 1
    Thank you for teaching me this! By the way is this an acceptable and perhaps a preferred way to perform configuration on, say, a Javascript (Node) project? Are there any drawbacks to this? – MadPhysicist Jul 23 '17 at 02:01
  • I've never done a Node project but using environment variables to define things like API keys can translate across languages. You should be fine using this approach with Node. – Phillip Cutter Jul 23 '17 at 15:41
  • According to [Subodh Ghulaxe](https://stackoverflow.com/a/33448470/7203225) , you could write something like `var apiKey = process.env.API_KEY;` to access an environment variable if it's named "API_KEY" in Node. – Phillip Cutter Jul 23 '17 at 15:55
  • 1
    A fair amount of these features have been handled nicely by the `django-environ` package. I can highly recommend it: https://github.com/joke2k/django-environ It completely separates your secrets into a single `.env` file, separate from any Python code. – FlipperPA Jul 23 '17 at 23:59
  • @FlipperPA Thanks for pointing me to this tool. I guess, I am still failing to see how it is an improvement. Perhaps I am misunderstanding the whole idea of separating the code and config. That is, one is still going to need to drag a file with configurations between environments. I am also wondering if it will work in production with WSGI and Apache setup? – MadPhysicist Aug 12 '17 at 22:18