Releases: vitalik/django-ninja
1.6.2
What's Changed
- allow
"app_label.ModelName"format for ModelSchemamodelby @andreasnuesslein in #1590
New Contributors
- @andreasnuesslein made their first contribution in #1590
Full Changelog: v1.6.1...v1.6.2
1.6.1
1.6.0
What's New
Idempotent Router(s)
Routers are now reusable and can be mounted to multiple APIs or multiple times within the same API. Decorators, auth, tags, and throttle settings are fully isolated between mounts.
router = Router(tags=["shared"])
@router.get("/items")
def list_items(request):
return [{"id": 1}]
# Mount same router to multiple APIs
api_v1 = NinjaAPI(urls_namespace="v1")
api_v1.add_router("/", router)
api_v2 = NinjaAPI(urls_namespace="v2")
api_v2.add_router("/", router) # !!! Before this was giving an errorCursor Pagination
New CursorPagination class for stable pagination over frequently changing datasets. Uses base64-encoded cursor tokens instead of offsets, ensuring consistent results even when items are added or removed.
from ninja.pagination import paginate, CursorPagination
@api.get("/events", response=list[EventSchema])
@paginate(CursorPagination, ordering=("-created",), page_size=20)
def list_events(request):
return Event.objects.all()Status Return
New Status class for explicitly returning HTTP status codes. Replaces the old tuple syntax (status_code, body) which is now deprecated.
from ninja import Status
@api.post("/login", response={200: Token, 401: Message})
def login(request, payload: Auth):
if not valid:
return Status(401, {"message": "Unauthorized"})
return Status(200, {"token": token})Skip Re-validation
When returning a Pydantic model instance that already matches the response schema, Django Ninja now skips redundant validation and directly serializes — a nice performance boost.
@api.get("/user", response=UserOut)
def get_user(request):
return UserOut(id=1, name="John") # skips re-validationStreaming Responses (JSONL & SSE)
First-class streaming support with automatic schema validation for each chunk. Supports both JSONL and Server-Sent Events formats.
from ninja.streaming import JSONL, SSE
@api.get("/items", response=JSONL[Item])
def stream_items(request):
for i in range(100):
yield {"name": f"item-{i}", "price": float(i)}
@api.get("/events", response=SSE[Item])
async def stream_events(request):
async for item in get_items():
yield itemDetails
- Idempotent router(s) by @vitalik in #1622
- Cursor pagination by @janrito in #1657
- Status return, Skip revalidation by @vitalik in #1684
- Streaming improvement by @vitalik in #1685
- python 3.14 compatibility (namespace annotations) by @vitalik in #1688
- Propose docs clarifications for view and operational decorators by @martinsvoboda in #1689
- Optional Union fix by @Nuung in #1690
New Contributors
Full Changelog: v1.5.3...v1.6.0
1.6.0 beta1
Note: This is beta release which is still testing - we encorage you to test this release as well and provide feedback
What's New
Idempotent Router(s)
Routers are now reusable and can be mounted to multiple APIs or multiple times within the same API. Decorators, auth, tags, and throttle settings are fully isolated between mounts.
router = Router(tags=["shared"])
@router.get("/items")
def list_items(request):
return [{"id": 1}]
# Mount same router to multiple APIs
api_v1 = NinjaAPI(urls_namespace="v1")
api_v1.add_router("/", router)
api_v2 = NinjaAPI(urls_namespace="v2")
api_v2.add_router("/", router) # !!! Before this was giving an errorCursor Pagination
New CursorPagination class for stable pagination over frequently changing datasets. Uses base64-encoded cursor tokens instead of offsets, ensuring consistent results even when items are added or removed.
from ninja.pagination import paginate, CursorPagination
@api.get("/events", response=list[EventSchema])
@paginate(CursorPagination, ordering=("-created",), page_size=20)
def list_events(request):
return Event.objects.all()Status Return
New Status class for explicitly returning HTTP status codes. Replaces the old tuple syntax (status_code, body) which is now deprecated.
from ninja import Status
@api.post("/login", response={200: Token, 401: Message})
def login(request, payload: Auth):
if not valid:
return Status(401, {"message": "Unauthorized"})
return Status(200, {"token": token})Skip Re-validation
When returning a Pydantic model instance that already matches the response schema, Django Ninja now skips redundant validation and directly serializes — a nice performance boost.
@api.get("/user", response=UserOut)
def get_user(request):
return UserOut(id=1, name="John") # skips re-validationStreaming Responses (JSONL & SSE)
First-class streaming support with automatic schema validation for each chunk. Supports both JSONL and Server-Sent Events formats.
from ninja.streaming import JSONL, SSE
@api.get("/items", response=JSONL[Item])
def stream_items(request):
for i in range(100):
yield {"name": f"item-{i}", "price": float(i)}
@api.get("/events", response=SSE[Item])
async def stream_events(request):
async for item in get_items():
yield itemDetails
- Idempotent router(s) by @vitalik in #1622
- Cursor pagination by @janrito in #1657
- Status return, Skip revalidation by @vitalik in #1684
- Streaming improvement by @vitalik in #1685
- python 3.14 compatibility (namespace annotations) by @vitalik in #1688
- Propose docs clarifications for view and operational decorators by @martinsvoboda in #1689
- Optional Union fix by @Nuung in #1690
New Contributors
Full Changelog: v1.5.3...v1.6.0b1
1.5.3
v1.5.2
A minor update
What's Changed
- Updated JS bundles to latest versions
- Update django-pydantic.md by @thornycrackers in #1632
- Fix missing trove classifiers by @ulgens in #1627
- Centralize "preview: true" config for ruff by @ulgens in #1629
New Contributors
- @thornycrackers made their first contribution in #1632
- @ulgens made their first contribution in #1627
Full Changelog: v1.5.1...v1.5.2
1.5.1
What's Changed
- Add dark mode favicons and template to overwrite favicons by @dpgraham4401 in #1587
- Fixed pagination override in case of RouterPaginated by @Lokker29 in #1608
- fix: Use serialization_alias in OpenAPI spec when by_alias=True by @OscarVanL in #1606
- Fix optional query params with None default (issue #1607) by @Vincent-Ngobeh in #1614
Misc
- Support Django 6.0 by @gvangool in #1613
- Bump actions/checkout from 3 to 6 by @dependabot[bot] in #1609
New Contributors
- @dpgraham4401 made their first contribution in #1587
- @Lokker29 made their first contribution in #1608
- @Vincent-Ngobeh made their first contribution in #1614
Full Changelog: v1.5.0...v1.5.1
1.5.0
What's New
- Global/Router decorators (aka middlewares) by @vitalik in #1525
- Annotation-based filtering in FilterSchema by @l1b3r in #1514
- pydantic 2.12 compatibility by @vitalik in #1561
^+Fix issues with nested default dicts by @HeyHugo in #1582- Fix sync authentication with async operations by @bellini666 in #1478
- Custom items_attribute in pagination by @ziima in #1569
Changes
- Fix use of
PathExwithAnnotatedtypes by @jceipek in #1574 - Fix paginate_queryset annotations by @ziima in #1570
- Remove Deprecated Config class support by @vitalik in #1528
- Remove deprecated csrf argument by @vitalik in #1524
- fix PatchDict errors with inherited schemas #1324 by @LeandroDeJesus-S in #1480
- fix: Merge openapi_extra list elements instead of overwrite by @OscarVanL in #1517
Misc
- Update CI and packaging for Django 5.2 and Python 3.13 support by @mahdirahimi1999 in #1481
- fix: fixing typo in code example for custom docs viewer by @jkeyes in #1023
- fix "Type of "paginate" is partially unknown" by @pradishb in #1503
- Fix typo in django-pydantic.md by @Komorebi4829 in #1531
- Fix minor typo in Update file-params.md by @ludde127 in #1521
- fix typo in "whatsnew_v1.md" by @mohassan-dev in #1498
- 3.14 matrix by @vitalik in #1565
- Add python 3.14 to test matrix by @pinguin999 in #1562
New Contributors
- @ziima made their first contribution in #1570
- @HeyHugo made their first contribution in #1582
- @mahdirahimi1999 made their first contribution in #1481
- @pradishb made their first contribution in #1503
- @ludde127 made their first contribution in #1521
- @LeandroDeJesus-S made their first contribution in #1480
- @bellini666 made their first contribution in #1478
- @Komorebi4829 made their first contribution in #1531
- @OscarVanL made their first contribution in #1517
Chances since Beta1
Full Changelog: v1.5.0b1...v1.5.0b2
1.5.0 b2
What's New
- Global/Router decorators (aka middlewares) by @vitalik in #1525
- Annotation-based filtering in FilterSchema by @l1b3r in #1514
- pydantic 2.12 compatibility by @vitalik in #1561
^+Fix issues with nested default dicts by @HeyHugo in #1582- Fix sync authentication with async operations by @bellini666 in #1478
- Custom items_attribute in pagination by @ziima in #1569
Changes
- Fix use of
PathExwithAnnotatedtypes by @jceipek in #1574 - Fix paginate_queryset annotations by @ziima in #1570
- Remove Deprecated Config class support by @vitalik in #1528
- Remove deprecated csrf argument by @vitalik in #1524
- fix PatchDict errors with inherited schemas #1324 by @LeandroDeJesus-S in #1480
- fix: Merge openapi_extra list elements instead of overwrite by @OscarVanL in #1517
Misc
- Update CI and packaging for Django 5.2 and Python 3.13 support by @mahdirahimi1999 in #1481
- fix: fixing typo in code example for custom docs viewer by @jkeyes in #1023
- fix "Type of "paginate" is partially unknown" by @pradishb in #1503
- Fix typo in django-pydantic.md by @Komorebi4829 in #1531
- Fix minor typo in Update file-params.md by @ludde127 in #1521
- fix typo in "whatsnew_v1.md" by @mohassan-dev in #1498
- 3.14 matrix by @vitalik in #1565
- Add python 3.14 to test matrix by @pinguin999 in #1562
New Contributors
- @ziima made their first contribution in #1570
- @HeyHugo made their first contribution in #1582
- @mahdirahimi1999 made their first contribution in #1481
- @pradishb made their first contribution in #1503
- @ludde127 made their first contribution in #1521
- @LeandroDeJesus-S made their first contribution in #1480
- @bellini666 made their first contribution in #1478
- @Komorebi4829 made their first contribution in #1531
- @OscarVanL made their first contribution in #1517
Chances since Beta1
Full Changelog: v1.5.0b1...v1.5.0b2