Skip to content

Django Extension

New in 2.0.0

Dynaconf extension for Django works by patching the settings.py file with dynaconf loading hooks, the change is done on a single file and then in your whole project. Every time you call django.conf.settings you will have access to dynaconf attributes and methods.

Ensure dynaconf is installed on your env pip install dynaconf[yaml]

Initialize the extension

You can manually append at the bottom of your django project's settings.py the following code:

# HERE STARTS DYNACONF EXTENSION LOAD (Keep at the very bottom of settings.py)
# Read more at https://www.dynaconf.com/django/
import dynaconf  # noqa
settings = dynaconf.DjangoDynaconf(__name__)  # noqa
# HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line)

Or optionally you can, on the same directory where your manage.py is located run:

export DJANGO_SETTINGS_MODULE=yourapp.settings
$ dynaconf init

# or passing the location of the settings file

$ dynaconf init --django yourapp/settings.py

Dynaconf will append its extension loading code to the bottom of your yourapp/settings.py file and will create settings.toml and .secrets.toml in the current folder (the same where manage.py is located).

Tip

Take a look at tests_functional/django_example

Using DJANGO_ environment variables

Then django.conf.settings will work as a dynaconf.settings instance and DJANGO_ will be the global prefix to export environment variables.

Example:

export DJANGO_DEBUG=true     # django.conf.settings.DEBUG
export DJANGO_INTVALUE=1     # django.conf.settings['INTVALUE']
export DJANGO_HELLO="Hello"  # django.conf.settings.get('HELLO')

Tip

If you don't want to use DJANGO_ as prefix for envvars you can customize by passing a new name e.g: dynaconf.DjangoDynaconf(__name__, ENVVAR_PREFIX_FOR_DYNACONF="FOO") then export FOO_DEBUG=true


You can also set nested dictionary values. For example, let's say you have a configuration like this:

# settings.py

...
DATABASES = {
    'default': {
        'NAME': 'db',
        'ENGINE': 'module.foo.engine',
        'ARGS': {'timeout': 30}
    }
}
...

And now you want to change the values of ENGINE to other.module, via environment variables you can use the format ${ENVVAR_PREFIX}_${VARIABLE}__${NESTED_ITEM}__${NESTED_ITEM}

Each __ (dunder, a.k.a double underline) denotes access to nested elements in a dictionary.

So:

export DYNACONF_DATABASES__default__ENGINE=other.module

will result in

DATABASES = {
    'default': {
        'NAME': 'db',
        'ENGINE': 'other.module',
        'ARGS': {'timeout': 30}
    }
}

Warning

Notice that casing is important for Django settings, so DYNACONF_DATABASES__default__ENGINE is not the same as DYNACONF_DATABASES__DEFAULT__ENGINE you must use the first which matched the proper django settings.

Read more on environment variables

Settings files

You can also have settings files for your Django app.

In the root directory (the same where manage.py is located) put your settings.{yaml, toml, ini, json, py} and .secrets.{yaml, toml, ini, json, py} files and then define your environments [default], [development] and [production].

To switch the working environment the DJANGO_ENV variable can be used, so DJANGO_ENV=development to work in development mode or DJANGO_ENV=production to switch to production.

If you don't want to manually create your config files take a look at the CLI

Tip

.yaml is the recommended format for Django applications because it allows easily writing complex data structures. Nevertheless, feel free to choose any format you are familiar with.

Important

To use $ dynaconf CLI the DJANGO_SETTINGS_MODULE environment variable must be defined.

Customizations

Loading settings

It is possible to customize how your django project will load settings.

Example: you want your users to customize a settings file defined in export PROJECTNAME_SETTINGS=/path/to/settings.toml and you want environment variables to be loaded from PROJECTNAME_VARNAME

To achieve that, edit django settings.py and modify the dynaconf extension part:

from:

# HERE STARTS DYNACONF EXTENSION LOAD
...
settings = dynaconf.DjangoDynaconf(__name__)
# HERE ENDS DYNACONF EXTENSION LOAD

to:

# HERE STARTS DYNACONF EXTENSION LOAD
...
settings = dynaconf.DjangoDynaconf(
    __name__,
    ENVVAR_PREFIX_FOR_DYNACONF='PROJECTNAME',
    ENV_SWITCHER_FOR_DYNACONF='PROJECTNAME_ENV',
    SETTINGS_FILE_FOR_DYNACONF='/etc/projectname/settings.toml',
    ENVVAR_FOR_DYNACONF='PROJECTNAME_SETTINGS',
    INCLUDES_FOR_DYNACONF=['/etc/projectname/plugins/*'],
)
# HERE ENDS DYNACONF EXTENSION LOAD

Variables on environment can be set/override using PROJECTNAME_ prefix e.g: export PROJECTNAME_DEBUG=true.

The working environment can now be switched using export PROJECTNAME_ENV=production it defaults to development.

Your settings are now read from /etc/projectname/settings.toml (dynaconf will not perform search for all the settings formats). This settings location can be changed via envvar using export PROJECTNAME_SETTINGS=/other/path/to/settings.py{yaml,toml,json,ini}

You can have additional settings read from /etc/projectname/plugins/* any supported file from this folder will be loaded.

You can set more options, take a look at configuration

Use Django functions inside custom settings

If you need to use django functions inside your settings, you can register custom converters with the add_converters utility.

When defining those in settings.py, there are some django functions that can't be imported directly in the module scope. Because of that, you may add them in a hook that executes after loading.

For example, if you need to use reverse_lazy, you might do this:

# myprj/settings.py

import dynaconf

def converters_setup():
    from django.urls import reverse_lazy  # noqa

    dynaconf.add_converter("reverse_lazy", reverse_lazy)

settings = dynaconf.DjangoDynaconf(__name__, post_hooks=converters_setup)

# HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line)

And then the following code would work:

# settings.yaml

default:
    ADMIN_NAMESPACE: admin
    LOGIN_URL: "@reverse_lazy @format {this.ADMIN_NAMESPACE}:login"

Note

Some common converters may be added to Dynaconf in future releases. See #865

For gettext, see #648

Reading Settings on Standalone Scripts

The recommended way to create standalone scripts is by creating management commands inside your Django applications or plugins.

The examples below assume you have DJANGO_SETTINGS_MODULE environment variable set, either by exporting it to your env or by explicitly adding it to os.environ dictionary.

Important

If you need the script to be available out of your Django Application Scope, prefer using settings.DYNACONF.configure() instead of the common settings.configure() provided by Django. The latter would cause dynaconf to be disabled.

After all, you probably don't need to call it, as you have DJANGO_SETTINGS_MODULE exported.

Common case

# /etc/my_script.py

from django.conf import settings
print(settings.DATABASES)

Explicitly adding the setting module

# /etc/my_script.py

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'foo.settings'

from django.conf import settings
print(settings.DATABASES)

When you need the configure

Calling DYNACONF.configure() is needed when you want to access dynaconf special methods like using_env, get, get_fresh etc...

# /etc/my_script.py

from django.conf import settings
settings.DYNACONF.configure()
print(settings.get('DATABASES'))

Importing settings directly

This is recommended for the above case.

# /etc/my_script.py

from foo.settings import settings
print(settings.get('DATABASES'))

Importing settings via importlib

# /etc/my_script.py

import os
import importlib
settings = importlib.import_module(os.environ['DJANGO_SETTINGS_MODULE'])
print(settings.get('DATABASES'))

Testing on Django

Django testing must work out of the box!

Mocking envvars with django

But in some cases when you mock stuff and need to add environment variables to os.environ on demand for test cases it may be needed to reload the dynaconf.

To do that, write up your test case setup part:

import os
import importlib
from myapp import settings # NOTE: this uses your app module not django.conf

class TestCase(...):
    def setUp(self):
        os.environ['DJANGO_FOO'] = 'BAR'  # dynaconf should read it and set `settings.FOO`
        importlib.reload(settings)

    def test_foo(self):
        self.assertEqual(settings.FOO, 'BAR')

Using pytest and django

Install pip install pytest-django

Add to your conftest.py

project/tests/conftest.py

import pytest

@pytest.fixture(scope="session", autouse=True)
def set_test_settings():
    # https://github.com/dynaconf/dynaconf/issues/491#issuecomment-745391955
    from django.conf import settings
    settings.setenv('testing')  # force the environment to be whatever you want

Explicit mode

Some users prefer to explicitly load each setting variable inside the settings.py and then let django manage it in the usual way. This is possible, but keep in mind that doing so will prevent the usage of dynaconf methods like using_env, get.

Dynaconf will be available only on settings.py scope. On the rest of your application, settings are managed by Django normally.

# settings.py

import sys
from dynaconf import LazySettings

settings = LazySettings(**YOUR_OPTIONS_HERE)

DEBUG = settings.get('DEBUG', False)
DATABASES = settings.get('DATABASES', {
    'default': {
        'ENGINE': '...',
        'NAME': '...
    }
})
...

# At the end of your settings.py
settings.populate_obj(sys.modules[__name__], ignore=locals())

You can still change env with export DJANGO_ENV=production and also can export variables like export DJANGO_DEBUG=true

Note

Starting in 2.1.1 the ignore argument will tell Dynaconf to not override variables that already exist in the current settings file, remove it if you want all the existing local variables to be overwritten by dynaconf.

Known Caveats

  • If settings.configure() is called directly it disables Dynaconf, use settings.DYNACONF.configure()

Deprecation note

On old dynaconf releases the solution was to add dynaconf.contrib.django_dynaconf to INSTALLED_APPS as the first item. This still works but has some limitations so it is not recommended anymore.