CLI reference¶
dorm ships a single entry point: the dorm command. Every subcommand
loads your settings module (auto-discovered via the
DORM_SETTINGS_MODULE env var, or --settings) and your
INSTALLED_APPS, then dispatches.
dorm init¶
Scaffold a new project in the current directory.
dorm init # creates settings.py
dorm init --app blog # creates settings.py + blog/ with example User model
The generated settings.py is SQLite by default; switch the
DATABASES["default"] block to PostgreSQL when you're ready.
dorm makemigrations¶
Detect model changes and write a migration file.
dorm makemigrations # all installed apps
dorm makemigrations blog users # specific apps
dorm makemigrations --empty --name backfill_slugs blog
| Flag | Purpose |
|---|---|
--empty |
create a blank RunPython / RunSQL template |
--name NAME |
suffix for the file name (default: derived from operations) |
--check (3.3+) |
exit code 1 when the autodetector would write a migration; nothing is written. Wire into CI to catch model changes that ship without the matching migration |
--merge (3.2+) |
resolve a fork in the migration graph by writing a no-op merge migration whose dependencies = [...] references every leaf — see below |
--enable-pgvector |
scaffold a migration that enables the pgvector extension |
--settings PATH |
settings module to load |
Resolving merge conflicts in the migration graph (--merge)¶
Two developers branch off 0001_initial and each land their own
0002_*. After the merge commit the graph forks: both 0002_a and
0002_b declare 0001_initial as their parent and neither
references the other, so the loader can't linearise apply order.
dorm makemigrations --merge # default name: NNNN_merge.py
dorm makemigrations --merge --name reconcile_branches
--merge writes a new empty migration whose dependencies = [...]
lists every leaf, collapsing the fork back to a linear graph. The
merge migration carries no operations — it only re-points the
graph's tip; the diverging migrations stay applied as-is.
No-op when the graph is already linear (zero or one leaf): prints
No migration conflicts detected — every app has at most one leaf.
Nothing to merge. so it's safe to wire into CI / pre-merge gates.
dorm migrate¶
Apply pending migrations or roll back to a target.
dorm migrate # apply everything pending
dorm migrate blog # only the blog app
dorm migrate blog 0005 # forward or rollback to 0005
dorm migrate blog 0005_add_index # name prefix also works
dorm migrate blog zero # rollback every migration
| Flag | Purpose |
|---|---|
--dry-run / --plan (3.0+) |
print SQL only; don't touch the DB or update the recorder. --plan is an alias kept for users coming from Django |
--fake (3.0+) |
record every pending migration as applied without running its operations. Use when adopting dorm against a hand-managed legacy schema |
--fake-initial (3.0+) |
only fake the initial migration of each app, and only when its CreateModel target tables already exist |
--run-syncdb (3.1+) |
create tables for INSTALLED_APPS that ship NO migration files (legacy / hand-managed apps). Useful when adopting dorm incrementally |
--prune (3.1+) |
drop recorder rows for migrations whose source files no longer exist on disk (e.g. after squashmigrations). No DDL — only the bookkeeping is touched |
--verbosity N |
0 = silent, 1 = default, 2 = verbose |
--settings PATH |
settings module to load |
dorm showmigrations¶
List every migration and its applied status.
dorm squashmigrations¶
Collapse a contiguous range of migrations into one.
dorm squashmigrations blog 0042
dorm squashmigrations blog 0010 0042
dorm squashmigrations blog 0010 0042 --squashed-name initial
The result is <app>/migrations/<end>_<name>.py with
replaces = [...] listing the originals. Once every environment has
applied the squashed migration, you can delete the originals.
dorm sql¶
Print the CREATE TABLE DDL for a model.
dorm sql users.User # one model
dorm sql users.User blog.Post # several
dorm sql --all # every model in INSTALLED_APPS
Useful for sharing schemas with DBAs, seeding fixtures, or generating the SQL needed to bootstrap a non-managed read replica.
dorm dbcheck¶
Compare model definitions against the live database.
Reports drift (missing columns, hand-edited types, columns the model doesn't know about) and exits non-zero on any difference. Wire this into CI or a pre-deploy gate to catch missing migrations early.
dorm shell¶
Open an interactive Python REPL with dorm pre-configured.
If IPython is installed, you get IPython; otherwise the standard
REPL. Settings are loaded and INSTALLED_APPS are imported, so you
can from blog.models import Post and start querying right away.
dorm lint-migrations (3.0+)¶
Walk every migration in INSTALLED_APPS and emit findings for known
online-deploy footguns. Exits non-zero on findings — wire as a CI
pre-merge gate.
dorm lint-migrations
dorm lint-migrations --format json # JSON for CI tools
dorm lint-migrations --rule DORM-M001 # only this rule
dorm lint-migrations --rule DORM-M001 --rule DORM-M003
dorm lint-migrations --exit-zero # advisory: never fail CI
| Flag | Purpose |
|---|---|
--format text\|json |
output shape (default: text) |
--rule CODE |
restrict to a code; may repeat |
--exit-zero |
exit 0 even when findings exist |
--settings PATH |
settings module to load |
Suppress a finding for a single file with a # noqa: DORM-M00X
comment anywhere in the file. See the
Migration safety
section in the production guide for the full rule table.
dorm dbshell¶
Drop into the underlying database client (psql or sqlite3) with
credentials and database name pre-filled from settings.
dorm dbshell # connects to DATABASES["default"]
dorm dbshell --database replica # pick a different alias
The PostgreSQL password is passed via PGPASSWORD env var rather
than the connection string so it doesn't end up in your shell
history or ps output. The child process inherits your terminal —
exit it (\q for psql, .exit for sqlite3) to come back.
dorm dumpdata (2.1+)¶
Serialise model rows to JSON. With no positional argument every
concrete model in INSTALLED_APPS is dumped. Pass an app label or
app.ModelName to scope.
dorm dumpdata # everything → stdout
dorm dumpdata blog # only models in app "blog"
dorm dumpdata blog.Post users.User # specific models
dorm dumpdata --output fixtures/seed.json --indent 2
Output format (compatible with Django's dumpdata):
[
{"model": "blog.Author", "pk": 1, "fields": {"name": "Alice"}},
{"model": "blog.Article", "pk": 7, "fields": {
"title": "Hello", "author": 1, "tags": [3, 5]
}}
]
Foreign keys serialise as the target's primary-key value. M2M
relations serialise as a list of related PKs. Non-JSON-native types
(decimals, UUIDs, datetimes, durations, ranges, bytes) round-trip
through dedicated envelopes — the loader rebuilds the right Python
type via the field's to_python.
dorm loaddata (2.1+)¶
Load one or more JSON fixture files into the database.
dorm loaddata fixtures/seed.json
dorm loaddata fixtures/users.json fixtures/posts.json
dorm loaddata fixtures/seed.json --database replica
Each file is loaded inside a single transaction — a malformed record
rolls back to that file's start instead of leaving a partial restore.
M2M relations are inserted in a second phase, after every parent row
has landed. save() and signals are bypassed for performance;
Model.save() is the right path when you do want pre-save hooks to
fire.
dorm diff (4.0+)¶
Detects schema drift between the model registry and the live DB
schema. Compares information_schema (PG / DuckDB) or
sqlite_master (SQLite). Reports:
- Tables declared by models that don't exist in the DB.
- Tables in the DB that no model declares.
- Missing columns on tables that do exist on both sides.
- Columns whose type disagrees with the model.
dorm diff # human-friendly summary
dorm diff --json > drift.json # CI-friendly output
dorm diff --apps myapp.models # restrict the walk
dorm diff --alias replica # specific alias
Exit code: 0 clean, 1 drift detected. Designed as a
post-deploy CI gate: dorm diff || exit 1 aborts the release if a
migration didn't land.
dorm purge-deleted (4.0+)¶
Physically delete SoftDeleteModel rows whose deleted_at is older
than the given window. Cron-friendly: no interactive prompts,
exit 0 on success.
dorm purge-deleted --older-than 30d # 30 days
dorm purge-deleted --older-than 12h --dry-run # report counts only
dorm purge-deleted --older-than 90d --apps myapp.models
dorm purge-deleted --older-than 30d --alias archive
Duration suffixes: s/m/h/d/w or a bare integer (seconds).
Silently skips models whose table doesn't exist (typical in
multi-tenant deployments where the alias doesn't host every model).
dorm export-json-schema (4.0+)¶
Emits a Draft 2020-12 JSON Schema document per model. Designed for downstream validators (Ajv, Zod runtime), schema registries, and cross-language tooling.
dorm export-json-schema > schemas.json # stdout
dorm export-json-schema --out schemas/ # one .json per model
dorm export-json-schema --apps myapp.models --out schemas/
dorm export-json-schema --include-relations --out schemas/ # M2M nested
Type mapping: EmailField → format: "email", UUIDField →
format: "uuid", DateTimeField → format: "date-time",
CharField.max_length → maxLength. Nullable fields emit
type: ["string", "null"].
dorm help¶
Settings discovery¶
Every command resolves settings in this order:
--settings dotted.path.to.settingsDORM_SETTINGS_MODULE=dotted.path.to.settingsenv var- A
settings.pynext to the working directory (last-resort)
If none of these resolve, dorm exits with an explanatory error.
dorm inspectdb (2.1+)¶
Reverse-engineer a models.py snippet from the connected database.
Best-effort recovery of field types, FK references and db_table;
constraints / indexes / related_name / validators are not
introspected. Pipe the output into a file and edit::
dorm inspectdb > legacy/models.py
Use --database alias to introspect a non-default DATABASES entry.
dorm doctor (2.1+)¶
Audit the running configuration for production-mode footguns:
small MAX_POOL_SIZE, missing sslmode on remote PostgreSQL hosts,
foreign keys without an index, transient-error retry left disabled.
Exits non-zero on any warning, so it doubles as a pre-deploy gate::
dorm doctor
The doctor is conservative — it only warns when the rule of thumb is widely accepted. Tune to your workload before treating any single warning as gospel.
dorm createsuperuser (3.1+)¶
Mint a dorm.contrib.auth.User row with is_superuser=True. Pass
--password for non-interactive flows; omit it for an interactive
prompt that confirms the input.
dorm createsuperuser --email admin@example.com --password 'secret'
dorm createsuperuser --email admin@example.com # interactive prompt
dorm changepassword (3.1+)¶
Update an existing user's password:
dorm changepassword admin@example.com --password 'newsecret'
dorm changepassword admin@example.com # interactive prompt
Hash comparison is constant-time via hmac.compare_digest. The new
hash uses the configured default algorithm (PBKDF2 stdlib, or
Argon2 if [auth-argon2] is installed).
dorm flush (3.1+)¶
Delete every row from every managed table. Schema stays — only the
data goes. Confirms unless --noinput is passed:
PostgreSQL uses TRUNCATE … RESTART IDENTITY CASCADE; SQLite +
MySQL fall back to DELETE FROM.
dorm sqlmigrate (3.1+)¶
Print the SQL of a single migration without applying it:
Useful for review before running a sensitive migration on production data. The recorder is not updated.
dorm shell_plus (3.1+)¶
Alias for dorm shell — Django-extensions parity. The base shell
already auto-imports every model from INSTALLED_APPS into the
namespace, so the two commands behave identically; shell_plus is
exposed as muscle-memory friendly entry point.
dorm runscript (3.1+)¶
Run a Python file under the project's settings, with INSTALLED_APPS
preloaded. Mirrors django-extensions' runscript:
Extra positional args are forwarded as sys.argv[1:] so scripts
read CLI args the way they would under a normal interpreter.