In Django's system check framework, how do message levels and ids like security.W004 work, and what does SILENCED_SYSTEM_CHECKS suppress?
answer
- five levels, numeric like logging
- ERROR is where commands stop
- applabel dot letter plus number
- a list of ids in settings
- hidden and ignored, not fixed
basics
~20 sMessages carry a level (Debug to Critical); Error and Critical stop management commands, lower levels are printed. Ids follow applabel.X001, where X marks the level. SILENCED_SYSTEM_CHECKS lists ids whose messages are hidden and excluded from the pass/fail decision.
solid answer
~40 sEvery check message has a numeric **level** — `DEBUG` 10, `INFO` 20, `WARNING` 30, `ERROR` 40, `CRITICAL` 50 — usually set through the `Debug`, `Info`, `Warning`, `Error` and `Critical` classes. Messages at `ERROR` or above are **serious**: commands that run checks stop with `SystemCheckError`, while warnings and below are printed and the command continues; `check --fail-level` moves that threshold for the `check` command only. The **id** is `applabel.` plus a level letter (`C`, `E`, `W`, `I`, `D`) and a number, so `security.W004` is a warning from the security checks (HSTS not configured). `SILENCED_SYSTEM_CHECKS`, empty by default, lists ids to acknowledge permanently: matching messages are not printed, are counted in the `(N silenced)` summary, and do not count toward failure. It works per id, project-wide, so it is a standing decision rather than a fix.
code
python · 5 lines# settings/base.py
SILENCED_SYSTEM_CHECKS = [
# Legacy one-to-one links are ForeignKey(unique=True); conversion is scheduled.
"fields.W342",
]go deeper
Recall that Error and Critical stop commands, warnings are printed, and ids like security.W004 name each message so it can be looked up or silenced.
Explain the numeric levels, the applabel.X000 id pattern, --fail-level, and exactly what silencing hides and excludes.
Show discipline around the silence list: per-id, project-wide scope, comments and reviews, production-only entries, and never muting serious messages to ship.
Treat silenced ids as recorded exceptions to policy, owned and revisited on each upgrade rather than accumulated.
## Levels `django.core.checks` defines five numeric levels, deliberately similar to Python's `logging` levels: | Constant | Value | Class | Effect in a command that runs checks | |---|---|---|---| | `DEBUG` | 10 | `Debug` | Printed | | `INFO` | 20 | `Info` | Printed | | `WARNING` | 30 | `Warning` | Printed; command continues | | `ERROR` | 40 | `Error` | `SystemCheckError`; command does not run | | `CRITICAL` | 50 | `Critical` | `SystemCheckError`; command does not run | A message is **serious** when its level is at or above the threshold, which is `ERROR` everywhere by default. The `check` command alone accepts `--fail-level CRITICAL|ERROR|WARNING|INFO|DEBUG` to move that threshold, which is how a pipeline makes warnings fatal. When something is reported, the output groups messages under `CRITICALS`, `ERRORS`, `WARNINGS`, `INFOS` and `DEBUGS` and goes to stderr. ## Ids Each message may carry an `id`. The documented pattern is **`applabel.X001`**: - `applabel` is the app or area that owns the check: `models`, `fields`, `urls`, `security`, `admin`, `auth`, `staticfiles`, or your own `shipping`. - `X` is the level letter: `C` critical, `E` error, `W` warning, `I` info, `D` debug. - The number is allocated by the owner and must be unique within that app. So `security.W004` is a warning from the security checks — it reports that `SECURE_HSTS_SECONDS` is not set while `SecurityMiddleware` is enabled, and it is a deployment check that only `check --deploy` runs. `fields.E300`-style ids come from field checks, `urls.W002`-style ids from URL checks. The full catalogue is the system check reference in the docs, and the id is what you search for when a message appears. A printed message reads `<object>: (<id>) <msg>`, followed by a `HINT:` line when a hint exists; the object prefix is the model label for model checks and `?` when there is no object. ## SILENCED_SYSTEM_CHECKS `SILENCED_SYSTEM_CHECKS` is a list of ids, default `[]`. For each message whose id is in the list: 1. It is **not printed**. 2. It is counted in the footer, as in `System check identified no issues (1 silenced).` 3. It is **excluded from the failure decision**, for `check --fail-level` and for the implicit checks before other commands. Some consequences worth knowing: - Silencing is **by id and project-wide**. You cannot silence `fields.W342` (`unique=True` on a `ForeignKey`) for one field only; every such field in the project goes quiet. - The documentation presents silencing as the way to acknowledge **warnings** you have inspected. Django's code filters silenced ids at every level, so listing an `Error` id also stops it blocking commands — which removes a safety net rather than fixing anything. - A message **without an id** cannot be silenced, which is one reason custom checks should always set one. - New Django releases add ids, and some ids disappear: `models.W042`, the auto-created primary key warning, was raised from 3.2 to 5.2 and is gone in 6.0, so an entry for it in a 6.1 project silences nothing. ## Reading one message Take a line such as `shop.Order.customer: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.` followed by a hint. Reading it left to right: 1. `shop.Order.customer` is the `obj` — the field at fault, printed before the id. 2. `fields` is the area that owns the check; `W` says it is a **warning**, so commands keep running. 3. `342` is the number the field checks allocated; together with the prefix it is the stable id. 4. The message and hint say what to change; the id is what you would add to `SILENCED_SYSTEM_CHECKS` if you decide to keep the design. ## Using levels well in your own checks - Reserve `Error` for configurations that will break at runtime; developers cannot start `runserver` until they fix it. - Use `Warning` for "probably wrong" and for conditions that differ legitimately between environments. - Pair an environment-sensitive rule with a `deploy=True` registration if it only matters in production. ## Silencing versus fixing Treat each silenced id as a small architectural decision: keep the list in version control, comment every entry with the reason, keep production-only silences in the production settings module, and revisit the list on upgrades.
- Could you add an Error id to SILENCED_SYSTEM_CHECKS to unblock a deploy, and should you?Mechanically yes: Django excludes any silenced id from the failure decision, so the command would run. But an `Error` marks a configuration Django expects to break at runtime, and the docs present silencing as a way to acknowledge inspected warnings. Fix the cause, or narrow the rule in your own check, instead of muting a serious message project-wide.
- How does check decide what goes to stdout and what goes to stderr?When unsilenced messages are reported but none reaches the fail level, `BaseCommand.check()` writes the report to stderr; when nothing visible is reported, the short `System check identified no issues (N silenced).` line from the `check` command goes to stdout. Serious messages at the fail level are raised as `SystemCheckError`, which the command line prints to stderr before exiting with status 1.
saying these in an interview costs you the question
- SILENCED_SYSTEM_CHECKS silences a check for one chosen model only
- A Warning stops management commands just like an Error
- The letter in an id such as security.W004 is arbitrary
- Silencing a message fixes the underlying configuration
- Messages without an id can be silenced by their text