skip to content

In Django, why is django.conf.settings a lazy object, and when would you call settings.configure() instead of setting DJANGO_SETTINGS_MODULE?

level: middleimportance: should knowfreq 40%

answer

  1. nothing loads at import
  2. first attribute access triggers it
  3. exactly one of two mechanisms
  4. standalone use of Django pieces
  5. uppercase names only

basics

~20 s

django.conf.settings is a LazySettings proxy: importing it loads nothing, and the first attribute access imports the module named by DJANGO_SETTINGS_MODULE. settings.configure() supplies settings in code instead, for standalone use of Django components; call it once, before any setting is read.

solid answer

~40 s

`from django.conf import settings` gives a `LazySettings` proxy, so modules can import it before any configuration exists. On the first attribute read it runs its setup: it reads `DJANGO_SETTINGS_MODULE`, imports that module and builds a `Settings` object from the defaults in `global_settings.py` plus the module's **uppercase** names, caching each value as it is read. If the variable is missing it raises `ImproperlyConfigured` saying you must define `DJANGO_SETTINGS_MODULE` or call `settings.configure()`. `configure()` is the alternative for using Django pieces inside a larger program, such as rendering templates from a script or running a reusable app's tests. It must be called exactly once and before any access, otherwise it raises `RuntimeError: Settings already configured.` Use `settings.configured` to check, and call `django.setup()` afterwards if you need apps or the ORM.

go deeper

for a junior

Always import settings from django.conf, and know the error message that means DJANGO_SETTINGS_MODULE is not set.

for a middle

Explain the lazy proxy, what happens on first read, the uppercase rule, and when configure() replaces the environment variable.

for a senior

Use configure() safely in tools and reusable-app test harnesses, guarding with settings.configured and pairing it with django.setup().

for a principal

Decide how embedded or tool uses of Django get configuration so that library code never competes with the host over configure().

## Why settings are lazy Django code imports `from django.conf import settings` all over the place — in models, views, middleware and third-party apps. If importing that name loaded the settings module immediately, **import order** would decide whether anything works, and simply importing a Django module in a tool would crash when no settings exist. So `settings` is a **`LazySettings`** object: a proxy that does nothing until someone reads an attribute. ## What happens on the first read 1. Code reads `settings.PAYROLL_CURRENCY` (or any setting). 2. `LazySettings` sees it is not set up and reads the `DJANGO_SETTINGS_MODULE` environment variable. 3. If the variable is missing, it raises `ImproperlyConfigured`: "Requested setting PAYROLL_CURRENCY, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings." 4. Otherwise it builds a `Settings` object: first every uppercase name from `django/conf/global_settings.py`, then every **uppercase** name from your module. Lowercase names in the module are ignored. 5. A few settings are validated here — for example `ALLOWED_HOSTS` and `INSTALLED_APPS` must be lists or tuples. 6. Each value read is cached on the proxy; an empty `SECRET_KEY` raises `ImproperlyConfigured` when it is read. ## Why you import settings from django.conf The docs say code should not import from `global_settings` or from your own settings file. Importing `payroll.settings` directly bypasses: - the **defaults** for anything your module does not define; - the `--settings` option and the environment variable choice of module; - test tools such as `override_settings`, which swap what the proxy returns. ## When to use settings.configure() `configure()` supplies settings as keyword arguments instead of a module: ```python import django from django.conf import settings settings.configure( DEBUG=False, TEMPLATES=[{"BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": ["templates"]}], ) django.setup() ``` Typical uses: - a script that uses Django's template engine or forms to render payslips, without a full project; - a reusable app's test runner that configures a minimal project in code; - embedding Django components inside a larger program that owns its own configuration. ## The rules around configure() | Situation | Result | |---|---| | neither the variable nor `configure()` | `ImproperlyConfigured` on the first read | | `configure()` before any read | settings come from the keyword arguments plus defaults | | `DJANGO_SETTINGS_MODULE` set, a setting read, then `configure()` | `RuntimeError: Settings already configured.` | | `configure()` called twice | `RuntimeError: Settings already configured.` | | a lowercase keyword such as `debug=True` | `TypeError`: settings must be uppercase | The docs sum it up: use exactly one of `configure()` or `DJANGO_SETTINGS_MODULE` — "Not both, and not neither." The `settings.configured` property tells you whether setup already happened. Passing `default_settings=` replaces Django's defaults entirely, so it is rarely needed. When configured this way, Django also does not modify process environment variables such as the time zone. ## configure() is not setup() `configure()` only provides settings. Using the ORM, models or anything that needs installed apps also requires `django.setup()`, which loads settings, configures logging and populates the app registry. Management commands and the WSGI/ASGI entry points call it for you. ## What an interviewer is listening for A middle candidate explains the lazy proxy and the first-read trigger, recognises the "settings are not configured" error, and knows `configure()` is for standalone use, called once before any access, followed by `django.setup()` when apps are needed.

  • Why is a lowercase variable in settings.py not available through django.conf.settings?
    When Django builds the `Settings` object it copies only names that are entirely uppercase, both from `global_settings.py` and from your module. Lowercase names are treated as helpers local to the module, so `settings.payroll_currency` raises `AttributeError` even though the module defines it.
  • How can library code avoid calling configure() twice?
    Check `settings.configured` first and only call `settings.configure(...)` when it is `False`. Because reading any setting also triggers setup from `DJANGO_SETTINGS_MODULE`, the check must happen before the library reads a setting.

The settings object is like a sealed envelope handed out at the door: everyone can carry it, but it is only opened, once, when someone first needs to read a line from it. After that, you cannot swap the letter inside.

saying these in an interview costs you the question

  • Imports the project's settings module directly instead of django.conf.settings
  • Calls settings.configure() after some code already read a setting
  • Expects lowercase names in settings.py to become settings
  • Believes configure() alone makes models and the ORM usable
  • Thinks importing django.conf.settings loads the settings module