Laurence Mercer

Understanding Wagtail's settings files (base.py, dev.py, production.py, and local.py)

Unlike Django, which, by default, generates a single settings.py file, Wagtail generates three settings files—base.py, dev.py, and production.py. In combination with a fourth, local.py, which can be created manually if required, these files help manage settings configurations across different environments.

This post discusses the purpose of these files, the settings flow (hierarchy), and how to switch between settings environments.

The Wagtail settings folder structure

By default, when creating a Wagtail project using the command wagtail start, a folder structure is generated based upon Wagtail's standard project template. Within this structure, Wagtail generates a settings folder like so:

(Note: The location of the settings folder will vary depending upon the additional parameter given when running wagtail start. For example, as shown here, wagtail start core will create the settings folder etc. inside a folder named core).

# tree (abridged)
lm/
├── core/
│   ├── settings/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── dev.py
│   │   └── production.py
│   ├── __init__.py
│   ├── apps.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

Purpose of the settings files

As outlined in the Wagtail documentation, each settings file serves a distinct role:

  • base.py
    • Contains shared settings used in both development and production environments. Most configuration will likely reside here.
  • dev.py
    • Contains settings specific to the development environment, such as features pertaining to debugging and local testing.
  • production.py
    • Contains settings specific to the production environment, such as features pertaining to security and performance.
  • local.py (optional, can be added if required)
    • Contains settings specific to a particular machine.

The settings flow (hierarchy)

By default, both dev.py and production.py begin by importing everything from base.py:

# core/settings/dev.py, core/settings/production.py
from .base import *

and then end by trying to import everything from local.py:

# core/settings/dev.py, core/settings/production.py
try:
    from .local import *
except ImportError:
    pass

As inferred, therefore, the default settings flow is:

  • dev.py and production.py import all settings from base.py
  • dev.py and production.py then optionally override or add environment-specific settings
  • dev.py and production.py then try to import all settings from local.py, which has the final say in overriding any setting

Switching between settings environments

Django uses the DJANGO_SETTINGS_MODULE environment variable to determine which settings file to load. As the Django documentation notes:

When you use Django, you have to tell it which settings you're using. Do this by using an environment variable, DJANGO_SETTINGS_MODULE.
The value of DJANGO_SETTINGS_MODULE should be in Python path syntax, e.g. mysite.settings. Note that the settings module should be on the Python sys.path.

Consequently, for a Wagtail project named core (such as that mentioned in the abridged tree shown earlier), it is necessary, in this case, to set the value of DJANGO_SETTINGS_MODULE to one of the following settings environment module paths:

  • core.settings.dev
  • core.settings.production

Setting the DJANGO_SETTINGS_MODULE environment variable

Default behaviour

Notably, Django/Wagtail attempts to set a default value for DJANGO_SETTINGS_MODULE in two places (manage.py and wsgi.py), both via the same call to setdefault:

# manage.py, core/wsgi.py
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings.dev")

However, as expected, setdefault will only set a value once per key (in this case, DJANGO_SETTINGS_MODULE). Therefore, if manage.py is run first, for example via python manage.py runserver, its DJANGO_SETTINGS_MODULE value will be set but the value subsequently given in wsgi.py will be ignored. Alternatively, for example on a production machine, if manage.py is not run, the value given in wsgi.py will be set.

Methods

The DJANGO_SETTINGS_MODULE value can set in various ways, depending upon the context. The following are several, more common, methods for doing so.

Method 1

Edit either manage.py or wsgi.py, and modify the default value. For example:

# manage.py, core/wsgi.py
# Change:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings.dev")
# to:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings.production")

Method 2

Again via code, set/override the value. For example:

os.environ["DJANGO_SETTINGS_MODULE"] = "core.settings.production"

Method 3

From the command line, use Django's --settings flag when running manage.py. For example:

python manage.py runserver --settings "core.settings.production"

Method 4

Again from the command line, export DJANGO_SETTINGS_MODULE. For example:

export DJANGO_SETTINGS_MODULE=core.settings.production
python manage.py runserver

Method 5

Use an environment variable helper/manager. For example, store DJANGO_SETTINGS_MODULE in a .env file and then use python-dotenv to parse the file and load the key-value pair as an environment variable.

# .env
DJANGO_SETTINGS_MODULE=core.settings.production
# manage.py
#!/usr/bin/env python
import sys

from dotenv import load_dotenv

load_dotenv()

if __name__ == "__main__":
    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

Return to blog