Kiwi
Kiwi

Reputation: 1185

Cannot use environment variables for settings in Django

In trying to find a place to store and save settings beyond settings.py and the database, I used an environment.json for environment variables. I import these in settings.py.

My problem is that when I try to change or store new values in my environment, env, settings.py does not notice the change - perhaps because the time and number of times settings.py is read by Django.

Is there a way I would be able to use my environment variables the way I want like attempted below?

# settings.py
import json
with open('/home/dotcloud/environment.json') as f:
    env = json.load(f)
EMAIL_HOST = env.get('EMAIL_PORT', '500')

# views.py
import json
def site_configuration(request):
    with open('/home/dotcloud/environment.json') as f:
        env = json.load(f)
    if request.method == 'POST':
        os.environ['EMAIL_PORT'] = request.POST['email_port']
    return render(request, ...)

# python manage.py shell demo
>>> import json
>>> with open('/home/dotcloud/environment.json') as f:
...     env = json.load(f)
... 
>>> project_settings.EMAIL_PORT
'500'
>>> env['EMAIL_PORT']
Traceback (most recent call last):
  File "<console>", line 1, in <module>
KeyError: 'EMAIL_PORT'
>>> env['EMAIL_PORT'] = "123"
>>> env['EMAIL_PORT']
'123'
>>> project_settings.EMAIL_PORT
'500'
>>> project_settings.EMAIL_PORT == env['EMAIL_PORT']
False'

And if not, how else could I store changeable settings that are retrieved by settings.py somewhere in my Django project?

Upvotes: 14

Views: 16825

Answers (2)

erynofwales
erynofwales

Reputation: 659

You might want to look into foreman (GitHub) or honcho (GitHub). Both of these look for a .env file in your current directory from which to load local environment variables.

My .env looks like this for most projects (I use dj-database-url for database configuration):

DATABASE_URL=sqlite://localhost/local.db
SECRET_KEY=<a secret key>
DEBUG=True

In your settings.py file, you can load these settings from os.environ like this:

import os
DEBUG = os.environ.get('DEBUG', False)

If there are required settings, you can assert their presence before trying to set them:

assert 'SECRET_KEY' in os.environ, 'Set SECRET_KEY in your .env file!'
SECRET_KEY = os.environ['SECRET_KEY']

I've been using this method of handling local settings for the last few projects I've started and I think it works really well. One caveat is to never commit your .env to source control. These are local settings that exist only for the current configuration and should be recreated for a different environment.

Upvotes: 37

Wolph
Wolph

Reputation: 80011

I see the question changed slightly, the original answers are still below but this one has a slightly different answer:


First, make sure you are using the right settings.py (print 'This file is being loaded' should do the trick).

Second, personally I would advise against using json files for config since it is less dynamic than Python files, but it should work regardless.

My recommended way of doing something like this:

  1. create a base_settings.py file with your standard settings
  2. create a settings.py which will be your default settings import. This file should have a from base_settings import * at the top to inherit the base settings.
  3. If you want to have a custom settings file, dotcloud_settings.py for example, simply add the from dotcloud_settings import settings (or base_settings) and set the environment variable DJANGO_SETTINGS_MODULE to dotcloud_settings or your_project.dotcloud_settings depending on your setup.

Do note that you should be very careful with importing Django modules from these settings files. If any module does a from django.conf import settings it will stop parsing your settings after that point.

As for using json files, roughly the same principle of course:

  • Once again, make sure you don't have anything that imports django.conf.settings here
  • Make all of the variables within your json file global to your settings file:

    import json with open('/home/dotcloud/environment.json') as f: env = json.load(f) # A little hack to make all variables within our env global globals().update(env)


Regardless though, I'd recommend turning this around and letting the settings file import this module instead.

Also, Django doesn't listen to environment variables by default (besides the DJANGO_SETTINGS_MODULE so that might be the problem too.

Upvotes: 7

Related Questions