Skip to content

Commands and checks

Management commands, the unasync tool and system checks. See Code generation and System checks.

manage.py devx_scaffold

Generate typed schemas, a CRUD controller and tests for a model.

Argument Type Default Description
model value — app_label.ModelName, e.g. blog.Article
--check flag — report drift between models and the schemas of mounted controllers
--output value — module file (default: /api/.py)
--tests value — test file (default: /tests/test__api.py)
--read list — fields of the output schema
--write list — fields of the input schema
--owner value — foreign key to the user (sets owner_field)
--async flag — generate async operations
--no-tests flag — do not write the test file
--force flag — overwrite existing files
--print flag — print instead of writing

manage.py devx_openapi

Export a NinjaAPI's OpenAPI schema, or generate a typed client from it.

Argument Type Default Description
api value — dotted path to a NinjaAPI, e.g. config.urls.api
--format one of json, typescript, python 'json' json (schema), typescript (types + fetch client) or python (httpx clients)
--python-style one of pydantic, typeddict 'pydantic' python models: pydantic (validated, with constraints) or typeddict
--output value — file to write (default: print)
--path-prefix value — override the API root path (default: from urls)
--check flag — fail if --output is missing or outdated (for CI)
--against value — compare with a previous OpenAPI document and fail on breaking changes; with --output the new document is written afterwards

manage.py devx_inspect

Show the resolved policy of mounted controllers: scoping, permissions, transaction, pagination, relations and operations.

Argument Type Default Description
target value — A controller path (app.api.PostController) or a mounted route prefix (/v1/posts). Without it, inspect every controller of the configured APIs.
--json flag — emit JSON instead of a tree

manage.py devx_doctor

Findings beyond manage.py check: unindexed query fields, unenforced owner/tenant fields, unhinted N+1 risks, missing pagination or permissions, and soft-deleted models with globally unique fields.

Argument Type Default Description
target value — A controller path (app.api.PostController) or a mounted route prefix (/v1/posts). Without it, check every controller of the configured APIs.
--json flag — emit JSON instead of a table
--fail-on one of info, warn — exit 1 if a finding at or above this severity is found

manage.py devx_uploads

Clean expired pending uploads for a configured UploadController.

Argument Type Default Description
controller value — import path to the configured UploadController
--limit value 100 maximum pending records per run

manage.py devx_startapp

Create a Django app laid out for ninja-devx: a controller, schemas, a service and tests (Django's startapp with the ninja-devx template).

Argument Type Default Description
name value — Name of the app.
directory value — Optional destination directory, created if needed.
--template value the ninja-devx template Another template directory or archive.

Every other option of Django's startapp (--extension, --name, --exclude) is accepted.

manage.py devx_startproject

Create a runnable ninja-devx project: settings wired with request id, security header and hardening middleware, a health check, JSON logging, a database from DATABASE_URL, and a Postgres compose file (Django's startproject with a template).

Argument Type Default Description
name value — Name of the project.
directory value — Optional destination directory, created if needed.
--template value the ninja-devx template Another template directory or archive.
--no-docker flag — skip compose.yaml (no local Postgres)
--app value — also scaffold a first app with devx_startapp

Every other option of Django's startproject (--extension, --name, --exclude) is accepted.

manage.py devx_apikey

Create, revoke or rotate scoped API keys.

Argument Type Default Description
action one of create, revoke, rotate — what to do
--user value — username of the key owner (create)
--name value — label of the key (create)
--scope value [] granted scope, repeatable
--days value — expire after this many days
--rate value '' rate limit of the key, e.g. "1000/hour"
--prefix value — prefix of the key to revoke

manage.py devx_webhooks

deliver: send due webhook deliveries (once, or continuously with --loop). generate-key: print a new WEBHOOK_SECRET_KEYS key. encrypt-secrets: encrypt stored secrets with the first key (also after rotation).

Argument Type Default Description
action one of deliver, stats, prune, retry, generate-key, encrypt-secrets — what to do
--database value — outbox database alias
--days value 30 retain terminal events this many days
--delivery-id value — one unclaimed delivery to replay
--limit value 100 deliveries per batch
--timeout value 10.0 seconds per request
--loop flag — keep polling
--interval value 2.0 seconds between polls
--allow-http flag — also send to http:// URLs (development)
--allow-private-networks flag — also send to loopback and private addresses (development)

manage.py devx_jobs

prune --older-than DAYS: delete terminal jobs older than this. retry : replay a failed or cancelled job synchronously.

Argument Type Default Description
action one of prune, retry — what to do
id value — job id (retry)
--older-than value — prune threshold
--retry-count value — extra attempts on failure (retry)

python -m ninja_devx.tooling.unasync

Argument Type Default Description
ASYNC.py:SYNC.py one or more pairs — source (async) and generated (sync) files
--check flag — fail when a generated file is outdated
--replace OLD=NEW repeatable — extra name mapping

Default renames: AbstractAsyncContextManager → AbstractContextManager, AsyncExitStack → ExitStack, AsyncGenerator → Generator, AsyncIterable → Iterable, AsyncIterator → Iterator, AsyncOperationHook → OperationHook, AsyncRepository → Repository, AsyncResolver → Resolver, StopAsyncIteration → StopIteration, __aenter__ → __enter__, __aexit__ → __exit__, __aiter__ → __iter__, __anext__ → __next__, aadd → add, aaggregate → aggregate, aauthenticate → authenticate, aauthenticated_user → authenticated_user, abulk_create → bulk_create, abulk_update → bulk_update, achange → change, acheck_object_permissions → check_object_permissions, acheck_permissions → check_permissions, aclose → close, acontains → contains, acount → count, acreate → create, acurrent_user → current_user, adelete → delete, aearliest → earliest, aexists → exists, aexplain → explain, afirst → first, aget → get, aget_object → get_object, aget_object_or_404 → get_object_or_404, aget_or_create → get_or_create, ahas_object_permission → has_object_permission, ahas_perm → has_perm, ahas_permission → has_permission, ahas_perms → has_perms, ain_bulk → in_bulk, aiterator → iterator, alast → last, alatest → latest, anext → next, arefresh_from_db → refresh_from_db, aremove → remove, arequest_context → request_context, arequest_scope → request_scope, arequest_user → request_user, aresolve → resolve, asave → save, asynccontextmanager → contextmanager, aupdate → update, aupdate_or_create → update_or_create, enter_async_context → enter_context.

System checks

Id Level Problem
ninja_devx.E001 error A CHECK_APIS entry cannot be imported or is not a NinjaAPI.
ninja_devx.E002 error search_fields, filter_fields, ordering_fields or default_ordering names a missing model field.
ninja_devx.W003 warning An output schema field is not a model field or attribute, and the schema does not resolve it.
ninja_devx.E004 error service_class needs constructor arguments, but the controller has no container.
ninja_devx.W005 warning An output field that VisibleTo can hide is required instead of optional.
ninja_devx.W006 warning A related hint or @requires_related lookup is not a relation of the model.
ninja_devx.W007 warning expand_rules[...].limit targets a relation that is not a plain reverse foreign key, so it is prefetched without a cap.
ninja_devx.E007 error aggregate_fields names a field that does not exist on the model.