ninja-devx
ninja-devx adds typed controllers and reusable resource policies to Django Ninja. It is intended for Django APIs that repeat ownership, tenant scoping, transaction, dependency-lifetime and error-handling rules across several endpoints. Services, repositories and contrib modules are optional.
Version 0.0.2 is the current alpha (0.0.1 was the first published release). See the scope and design rationale, comparison and support policy before adopting it.
class PostController(SoftDeleteMixin[Post, PostOut], CRUDController[Post, PostOut, PostIn]):
owner_field = "author"
search_fields = ("title", "body")
filter_fields = {"status": ("exact",), "created": ("gte", "lte")}
ordering_fields = ("created", "title")
@post("/{pk}/publish", response=PostOut, decorators=[idempotent()])
def publish(self, request: HttpRequest, post: Instance[Post]) -> Post:
post.status = Post.Status.PUBLISHED
post.save(update_fields=["status"])
return post
api = NinjaAPI(auth=django_auth)
mount(api, {"/posts": PostController}, prefix="/v1")
These lines give you:
- list endpoints with search, generated filters, enum-checked ordering and pagination
- retrieve, create, update and partial update
- soft delete, restore and an idempotent publish action
- owner-only writes and schema-derived relation loading
- 422 for model validation errors, and domain errors mapped without exception handlers
- declared error responses included in OpenAPI
Principles:
- Controllers produce
ninja.Routers and use Ninja authentication, pagination and serialization. Async stream preflight has a narrow operation-subclass integration that is tested against supported Ninja versions. - Layers without force: plain controllers, services, use cases or dishka interactors all fit, and none is required.
- Typed end to end: mypy strict and pyright strict pass, and the package has no
typing.Any. - Configuration errors raise at startup.
- Controller overhead is measured against function views with explicit budgets (see performance).
Requires Python 3.11+, Django 4.2+ and django-ninja 1.7.x (support policy).
pip install ninja-devx # extras: [guardian] [s3] [crypto] [orjson] [msgspec] [dishka] [svcs] [otel] [client] [contract]
Features
| Area | What you get | Docs |
|---|---|---|
| Controllers | @get/@post/... with typed options, scopes, lifecycle methods, plugins, use_case |
guide |
| Permissions | composable & | ~, Also(...), object-level, async, policies, AuthedRequest[User] |
guide |
| Object permissions | per-object grants (built-in table or django-guardian), DRF-style 404/403, lists filtered in SQL, sharing endpoints | guide |
| Errors | DomainError and typed ErrorMap rules per operation, controller, project; problem+json |
guide |
| CRUD | sync and async from one class, AutoCRUDController[Model], owner_field, Instance/Locked, filters, offset and cursor pagination, nested, configurable soft delete and routes, bulk (with per-item partial success), CSV/JSONL import and export, N+1 planner with explicit related/@requires_related hints and expand_rules capping ?expand= per parent, pluggable search_backend (PostgresSearch), nested writes (NestedWritesMixin) for a parent and its children in one request, API-level state transitions (TransitionsMixin), a metadata endpoint (MetaMixin) and an aggregation endpoint (AggregateMixin), TimeStamped/UserStamped/SoftDeletable model bases filled from the request |
guide |
| SaaS and HTTP | tenant_field multi-tenancy, ETag/304/If-Match optimistic locking, user/scope/tenant throttles, role-based read and write field visibility (VisibleTo/WriteVisibleTo), ?fields=/?expand= |
tenancy, caching, throttling, visibility |
| Layers | HTTP-free services, repositories, RequestContext, after-commit tasks with Celery/Dramatiq/RQ/Taskiq/Temporal/FastStream adapters, policies, selectors, in-memory fakes |
guide |
| CQRS and DDD | use_case/use_query command-query handlers, optional Command/Query markers, DomainEvent + EventBus (after commit), UnitOfWork |
guide |
| DI | Inject[T], Resolve(fn), a checked container with async factories, dishka and svcs adapters |
guide |
| Async | mode, one thread hop per unit of work, async hooks, loud lazy-load errors, unasync |
guide |
| Cross-cutting | hooks, LoggingHook, OpenTelemetry, atomic=True, idempotent() |
guide |
| Operations | router/API middleware and APIPlugin bundles, request ids, deprecation, rate limit and pagination headers, security headers, request hardening, response caching, health checks, orjson/msgspec renderers, structured per-request logs (RequestLogPlugin), X-Query-Count/X-Query-Time/X-Query-Plan in development (QueryExplainMiddleware), Accept-Version response downgrading (VersionedResponseMixin), pluggable throttle storage with an atomic Redis backend, Sensitive field masking in exports, validation errors and the audit log |
guide, operations |
| Optional integrations | scoped, rate-limited API keys, audit log with diffs, transactional outbox and signed, destination-validated webhooks with encrypted secrets, presigned S3 uploads, background jobs tracked as Job rows (start_job/@job, JobsController, devx_jobs), Django admin for the credential, audit, webhook and job records |
API keys, audit, webhooks, uploads, jobs |
| Quality | system checks (E001, E002, E004, E007, W003, W005, W006, W007), devx_scaffold --check schema drift, devx_openapi --against breaking-change gate, devx_inspect policy tree, devx_doctor configuration-risk findings, runtime N+1 detection over django-zeal, devx_startproject scaffolding a runnable project, schemathesis contract tests, OpenAPI snapshots, sample/samples payloads, assert_max_queries/assert_max_hops |
checks, inspecting, testing, N+1 and devx_doctor, starting a project |
| Code generation | devx_startapp, devx_scaffold with model constraints, TypeScript and validated pydantic Python clients with discriminated unions, cookie/multipart support and Python SSE iterators |
guide |
| Settings and translations | NINJA_DEVX project defaults; client-facing messages use Django's gettext, so you can ship your own catalog |
guide |
Start with the quickstart, then pick an example:
| Example | Shows |
|---|---|
quickstart |
a private notes API in one small file |
blog |
the tutorial: scaffolding, soft delete, nesting, generated clients |
recipes |
HackSoft, Cosmic-lite and dishka architectures passing the same tests |
saas |
multi-tenant tracker: roles, ETag/If-Match, cursors, throttles, field visibility, schemathesis |
async_api |
async-first orders: one thread hop per write, async dependencies, SSE |
Every option, parameter, setting and error code is listed with its type and default in the configuration reference, generated from the code.
Contributing and security
See CONTRIBUTING.md. Report vulnerabilities privately as described in SECURITY.md.
License
Development
For the disposable Docker test stack and release gates, see release validation.
uv sync --group docs
uv run pytest # --update-snapshots to accept OpenAPI changes
uv run ruff check . && uv run ruff format --check .
uv run mypy && uv run pyright # strict; tests/typing holds negative checks
for example in quickstart blog recipes saas async_api; do (cd examples/$example && uv run --project ../.. pytest -q); done
uv run python tools/generate_docs.py # regenerate docs/options after changing options or docstrings
uv run mkdocs serve # DJANGO_SETTINGS_MODULE=tests.settings for the reference
uv run python benchmarks/overhead.py --check benchmarks/budget.json
Metadata
Release files for ninja-devx 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ninja_devx-0.0.2.tar.gz | 778.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ninja_devx-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / ninja_devx-0.0.2.tar.gz
| Download URL | ninja_devx-0.0.2.tar.gz |
|---|---|
| Size | 778.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c6c7a27c045bd558b43ad4e210dfae69a7e26185b2431757e1150cc7ac64b2bd
|
|
BLAKE2b-256 checksum How to use checksums |
738bf010a41d9fd17718ddf2be268021a6521ae8fd92ca4ee1b14715f40ee295
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / ninja_devx-0.0.2-py3-none-any.whl
| Download URL | ninja_devx-0.0.2-py3-none-any.whl |
|---|---|
| Size | 355.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cd744987583ef3f6224b7014faeb2ebe43529163843582277c973697e6475e5a
|
|
BLAKE2b-256 checksum How to use checksums |
3484a3cd8f4484650a614c0a6d385dc726530841512be6f64d02124f2e42848c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log