skip to content

How does pytest-django decide which Django settings module to load, and what is the precedence between --ds, DJANGO_SETTINGS_MODULE and pytest.ini?

level: middleimportance: nice to knowfreq 26%

answer

  1. command line, environment, config file
  2. addopts to force the config
  3. manage.py and the Python path
  4. fixtures skip without settings

basics

~10 s

pytest-django takes the settings module from --ds first, then the DJANGO_SETTINGS_MODULE environment variable, then the DJANGO_SETTINGS_MODULE key in pytest's config file. Putting --ds in addopts makes the file win.

solid answer

~40 s

pytest-django resolves the settings module in a fixed order: the `--ds` command-line option, then the `DJANGO_SETTINGS_MODULE` environment variable, then a `DJANGO_SETTINGS_MODULE` key in the pytest configuration file (`pytest.ini`, `tox.ini` or `pyproject.toml`). The test header shows which source won, for example `settings: config.settings.test (from ini)`. Because the environment beats the ini file, a developer shell that exports the local settings module silently overrides the project's test settings; writing `addopts = --ds=config.settings.test` in the config makes the file's choice highest priority. Separately, `django_find_project` (on by default) looks for `manage.py` and adds its directory to the Python path so the module can be imported. If no settings are found, Django fixtures such as `client`, `rf` and `settings` skip with "no Django settings" rather than erroring.

go deeper

for a junior

Know the three places a settings module can come from: --ds, the environment variable and the pytest config file.

for a middle

Explain the precedence order, the addopts trick, and how django_find_project makes the module importable.

for a senior

Diagnose wrong-settings runs from the session header and design configuration that developer shells and CI cannot silently override.

for a principal

Standardise test settings across services so every pipeline and laptop runs the same configuration.

## Why it matters pytest knows nothing about Django until pytest-django configures it, and everything depends on **which settings module** it loads: the database the test database is derived from, the password hashers, `INSTALLED_APPS`, email backends. Loading the development settings instead of the test settings is a classic source of slow or confusing test runs. ## The precedence order pytest-django checks three sources, highest first: 1. **`--ds`** on the command line: `pytest --ds=config.settings.test`. 2. The **`DJANGO_SETTINGS_MODULE` environment variable**. 3. A **`DJANGO_SETTINGS_MODULE` key** in pytest's configuration file. ```ini # pytest.ini [pytest] DJANGO_SETTINGS_MODULE = config.settings.test addopts = --ds=config.settings.test ``` The second line is the documented trick for making the configuration file authoritative: options in `addopts` count as command-line options, so they beat the environment variable. | Source | Example | Beats | |---|---|---| | `--ds` (including via `addopts`) | `--ds=config.settings.test` | environment and ini key | | environment variable | `export DJANGO_SETTINGS_MODULE=config.settings.dev` | ini key | | ini key | `DJANGO_SETTINGS_MODULE = config.settings.test` | nothing | pytest-django prints the winner in the session header, for example `settings: config.settings.test (from ini)`, which is the first thing to check when tests behave as if they used the wrong settings. ## Making the module importable A dotted module path is useless if Python cannot import it: - The **`django_find_project`** ini option is **true by default**. pytest-django searches for a `manage.py` near the test paths and adds that directory to `sys.path`, reporting that it did so. - Projects with a non-standard layout can set `django_find_project = false` and manage the Python path themselves, for example with pytest's own `pythonpath` setting. - If the module cannot be imported, pytest-django stops with a message explaining the settings value and where it came from. ## What happens without settings When no settings module is configured at all, pytest-django stays out of the way for tests that do not need Django: Django-specific fixtures such as `client`, `rf` and `settings` call a helper that **skips the test with "no Django settings"**. That avoids crashing pure-Python test suites that happen to have pytest-django installed, but it can also hide a misconfiguration, so a CI job with unexpectedly many skips deserves a look. ## Practical setup - Keep a dedicated **test settings module** (fast password hasher, in-memory email, test-friendly storage). - Name it in the **configuration file**, and add `--ds` to `addopts` if developers export other settings in their shells. - For a one-off run against different settings, pass `--ds` explicitly on the command line; it overrides everything else. - There is a parallel `--dc` option and `DJANGO_CONFIGURATION` key for projects that use the third-party django-configurations package. ## A worked diagnosis A developer reports that tests take ten times longer on their laptop than on CI and that the test database appears on the shared development database server. The checklist: 1. Look at the session header. It reads `settings: config.settings.dev (from env)`. 2. Their shell profile exports `DJANGO_SETTINGS_MODULE=config.settings.dev` for `runserver`. 3. The environment beats the ini key, so the development settings were loaded: the default slow password hasher, development-only apps in `INSTALLED_APPS`, and a `DATABASES` entry pointing at the shared server. 4. Fix locally by unsetting the variable for test runs; fix for everyone by adding `addopts = --ds=config.settings.test` so the configuration file wins. The same header line is worth adding to CI logs review: it proves which settings a pipeline actually used. ## Related switches that often come up - **`--ds` versus `--dc`.** `--ds` names the settings module; `--dc` names a configuration class for projects using django-configurations, with the same option, environment, ini precedence. - **`--reuse-db` and `--create-db`.** Not about which settings load, but about what happens to the test database those settings describe; they are frequently added to `addopts` next to `--ds`. - **`--no-migrations`.** Builds the test database from the models instead of running migrations, trading migration coverage for speed. Knowing that all of these can live in `addopts` is what makes a project's pytest configuration a single, reviewable source of truth for how tests run.

  • Tests suddenly run against your local development settings even though pytest.ini names the test settings; what is the likely cause?
    The shell exports `DJANGO_SETTINGS_MODULE`, and the environment variable outranks the ini key. The session header will say `(from env)`. Unset the variable, or put `addopts = --ds=config.settings.test` in the configuration so the command-line source wins.

saying these in an interview costs you the question

  • Believing the pytest.ini key always wins over the environment variable
  • Thinking pytest-django reads the settings module from manage.py automatically
  • Assuming a missing settings module makes every test fail immediately
  • Saying --ds only works when no environment variable is set