Skip to content

Releases: wemake-services/django-modern-rest

Version 0.8.0

26 Apr 20:53
7b03066

Choose a tag to compare

In this version we focused on reworking on throttling internal API and our DjangoSession auth support.

Breaking changes

  • Breaking: Renamed APIRedirectError to RedirectTo, #922
  • Breaking: Split BaseThrottleBackend into BaseThrottleAsyncBackend
    and BaseThrottleSyncBackend, #942
  • Breaking: Renamed DjangoCache into SyncDjangoCache,
    added AsyncDjangoCache, #942
  • Breaking: Changed BaseThrottleBackend API: now it requires
    .incr and .get methods, the first one should ideally
    be an atomic increment, the second one is for reading objects only, #942
  • Breaking: Removed BaseThrottleAlgorithm.record method,
    now BaseThrottleAlgorithm.access must also record accesses.
    This will help to make throttling more atomic, #942

Migrations prompt

User-facing changes:

Apply this change to the code that uses `django-modern-rest`:
1. Replace `dmr.response.APIRedirectError` with `dmr.response.RedirectTo`
2. Replace `dmr.throttling.backend.DjangoCache`
   with `dmr.throttling.backend.SyncDjangoCache` for sync throttles 
   and with `dmr.throttling.backend.AsyncDjangoCache` for async throttles

Features

  • Added SyncRedis and AsyncRedis throttling backends, #977
  • Added RefreshTokenSyncController and RefreshTokenAsyncController
    to issue new access/refresh token pairs from a valid refresh token, #907
  • Added validate_negotiation metadata flag, so we can explicitly validate,
    that returned response followed the negotiation process, #711
  • Added accepted_header as a faster alternative
    to django's HttpRequest.accepts, #854

Bugfixes

  • Fixed OpenAPI schema for Django session auth
    when CSRF_USE_SESSIONS=True, #674
  • Fixed that itemSchema was possible to be rendered
    in OpenAPI 3.0.0 and 3.1.0, #908
  • Fixed response validation when global error handler returns
    HttpResponse with a different content type than the negotiated
    renderer, #711
  • Fixed collectstatic failure when using ManifestStaticFilesStorage, #927
  • Fixed datetime validation when using .to_response, #938
  • Fixed a bug that ObtainTokensAsyncController was not setting
    the request.auser attribute, #953
  • Fixed a bug that JWTSyncAuth was not setting request.auser, #953
  • Fixed ResponseNegotiator raising NotAcceptableError on streaming
    endpoints when Accept: text/event-stream was sent without
    application/json (the default browser EventSource case), which
    made 4xx/5xx error bodies and response validation crash with a 500
    instead of rendering the configured non-streaming default, #962
  • Fixed that original traceback was not shown
    for BaseSchemaGenerator.get_schema, #961

Misc

  • Optimized dmr_client and dmr_rf test fixtures to use msgspec
    for JSON encoding and decoding when available, #889 and #976
  • Optimized how per-endpoint throttle locks are used, #942

New Contributors

Full Changelog: 0.7.0...0.8.0

Version 0.7.0

14 Apr 16:19
dba07e8

Choose a tag to compare

Breaking changes

  1. Removed public OpenAPIView.dumps customization hook, #847
    If you customized schema output for OpenAPIJsonView, subclass
    the concrete view and override .get() instead.
    For JSON output, use dmr.openapi.core.dump.json_dump
    if you need the framework's default serializer
  2. Breaking: get_jwt is renamed to request_jwt, #868
  3. Breaking: ResponseSpecProvider.provide_response_specs is now
    an instance method, #877
  4. Breaking: new required router parameter added
    to Endpoint.get_schema and Controller.get_path_item, #879

Migration Prompt

Apply this change to the code that uses `django-modern-rest`:
1. Replace `OpenAPIView.dumps` usage with `dmr.openapi.core.dump.json_dump`
   usage
2. Change `dmr.security.jwt.auth.get_jwt` function
   to use `dmr.security.jwt.auth.request_jwt` instead, if user expects
   to always get a token back, add `strict=True` argument
3. Change `provide_response_specs` class method to be instance method,
   replace all `cls` usage with `self`
4. Add `router: Router` parameter to `Endpoint.get_schema`
   and `Controller.get_path_item` methods

Features

  • Added official PyPy 3.11+ support, #870
  • Added dmr.throttling package, #877
  • Added request.__drm_auth__ on all successful auth workflows, #868
  • Added request_auth helper function, #868
  • Added AuthenticatedHttpRequest type for better
    request: AuthenticatedHttpRequest[User]
    type annotations in controllers, #888
  • Added strict parameter to request_renderer and request_parser,
    added @overloads to both of these functions, #869
  • Added ResponseSpecMetadata type to represent
    headers and cookies with annotations, useful for error models, #882
  • Allow individual OpenAPI views to skip schema validation, #867
  • Added endpoint validator to prevent sync
    and async generator HTTP endpoints, #843
  • Added CSP-friendly templates for shipped OpenAPI UI views, #847
    SwaggerView, RedocView, ScalarView, and StoplightView
    now avoid inline scripts in DMR-managed templates.
    Final CSP compatibility still depends on the upstream renderer bundle.
  • Added tags and deprecated parameters to Router for OpenAPI metadata,
    #872. All operations in a router can now be grouped and marked as deprecated.

Fixes

  • Fixed that OpenAPI was revalidated on every .convert call, #867
  • Fixed missing request.auser() after JWTAsyncAuth, #884
  • Fixed ParameterMetadata missing __slots__, #890
  • Fixed SSEvent missing __slots__, #901
  • Fixed SSE protocol typing, #894
  • Fixed a bug when we were treating controllers with
    no api_endpoints as non-abstract, #894
  • Fixed a bug when you were not able to subclass
    a controller with a serializer, #873

Misc

  • Added dmr skill for agents to write better django-modern-rest code, #886
  • Switched from Make to just
    as a command runner

New Contributors

Full Changelog: 0.6.0...0.7.0

Version 0.6.0

09 Apr 14:35
588e2fa

Choose a tag to compare

In this release we significantly increased the performance of pydantic
workflows by introducing PydanticFastSerializer.

Снимок экрана 2026-04-06 в 17 17 19

No breaking changes in this release.

Features

  • Added PydanticFastSerializer to serialize and deserialize json
    objects directly, #830
  • Added support for complex pydantic fields inside
    TypedDict, @dataclass, etc models, when using PydanticSerializer
    and msgspec parsers / renderers, #842
  • Introduced official to_json_kwargs and to_model_kwargs class-level API
    for msgspec and pydantic serializers, #842
  • Added "Problem Details" or RFC-9457 support, #78
  • Added customizable json_module parameter to JsonParser and JsonRenderer
    to support alternative JSON backends like orjson, #857

Fixes

  • Fixed package metadata, #824
  • Fixed missing style, phone, color formats from OpenAPIFormat, #842
  • Fixes Django 5.2.13+ compat in DMRAsyncRequestFactory, #853

New Contributors

Full Changelog: 0.5.0...0.6.0

Version 0.5.0

05 Apr 17:52
dea0934

Choose a tag to compare

AKA "The first compiled version"

Снимок экрана 2026-04-04 в 11 46 53

This release will focus on better errors, performance, and stability.
No breaking changes will be made.

Features

  • Added mypyc support for compiling parts of the framework
    to run significantly faster, for example our compiled content
    negotiation is now 35 times faster then the Django's default one, #202
    See our https://django-modern-rest.readthedocs.io/en/latest/pages/deep-dive/performance.html#mypyc-compilation docs about that
  • Added older Django versions 4.2, 5.0, 5.1 official support, #803
  • Added official NamedTuple support, #774
  • Added timezone and pydantic-extra-types dependencies
    with [pydantic] extra, #802
  • Added exclude_semantic_responses options, #786
  • Added an option to override exclude_semantic_responses
    and no_validate_http_spec settings with None
  • Added a new way to resolve annotations for controllers:
    AnnotationsContext, #787
  • Added yaml view for OpenAPI schema, #745

Fixes

  • Fixed StreamingValidator swallowing errors
    when validate_events was True, but no event model was resolved, #780
  • Fixed dataclass instances serialization with PydanticSerializer
    without msgspec json renderer, #795
  • Fixed missing password OpenAPI format, #805
  • Fixes incorrect settings validation, #821

Misc

  • Added QuerySet tutorial, #792
  • Migrated from poetry to uv for dependency management
  • Set up automated secure publishing to PyPI, #823
  • Added CodSpeed integration for continous performance monitoring, #810

New Contributors

Full Changelog: 0.4.0...0.5.0

Version 0.4.0

29 Mar 18:52
1d8654c

Choose a tag to compare

AKA "The first version that I enjoy".

Breaking changes

  1. We changed how components are defined in controllers, #738
    Now components will be defined in method parameters, not in base classes.

  2. We removed dmr.controller.Blueprint, because it is not needed anymore.
    It was used to compose different classes with different parsing strategies.
    Since, it was only used for different parsing rules

  3. We removed drm.routing.compose_blueprints function,
    because there no Blueprints anymore :)

  4. We completely changed our SSE and streaming API, see #736
    Old API was removed, new one was introduced.
    dmr.sse package was moved to dmr.streaming.sse

We always ship AI prompts to all breaking changes.
So, it would be easier for you to migrate
to a newer version using AI tool of your choice.

Migration Prompt

To migrate django-modern-rest to version 0.4.0 and above, you need to:

  1. Load the latest documentation from https://django-modern-rest.readthedocs.io/llms-full.txt
  2. Convert component parsing from old class-based API to new method-based API.
    Before:
from dmr import Blueprint, Body
from dmr.routing import compose_blueprints
from dmr.plugins.pydantic import PydanticSerializer


class UserCreateBlueprint(
    Body[_UserInput],  # <- needs a request body
    Blueprint[PydanticSerializer],
):
    def post(self) -> _UserOutput:
        return _UserOutput(
            uid=uuid.uuid4(),
            email=self.parsed_body.email,
            age=self.parsed_body.age,
        )


class UserListBlueprint(Blueprint[PydanticSerializer]):
    def get(self) -> list[_UserInput]:
        return [
            _UserInput(email='first@example.org', age=1),
            _UserInput(email='second@example.org', age=2),
        ]


UsersController = compose_blueprints(UserCreateBlueprint, UserListBlueprint)

To:

from dmr import Controller, Body
from dmr.plugins.pydantic import PydanticSerializer


class UsersController(Controller[PydanticSerializer]):
    def get(self) -> list[_UserInput]:
        return [
            _UserInput(email='first@example.org', age=1),
            _UserInput(email='second@example.org', age=2),
        ]

    def post(self, parsed_body: Body[_UserInput]) -> _UserOutput:
        return _UserOutput(
            uid=uuid.uuid4(),
            email=self.parsed_body.email,
            age=self.parsed_body.age,
        )
  1. Replace all Blueprint and compose_blueprints references with a new API:
    Instead you must use Controller and different methods under a single class
  2. Now, change all @sse-based controllers to new SSEController API, from:
from collections.abc import AsyncIterator

import msgspec
from django.http import HttpRequest

from dmr.components import Headers
from dmr.plugins.msgspec import MsgspecSerializer
from dmr.sse import SSEContext, SSEResponse, SSEvent, sse


class HeaderModel(msgspec.Struct):
    last_event_id: int | None = msgspec.field(
        default=None,
        name='Last-Event-ID',
    )


async def produce_user_events(
    request_headers: HeaderModel,
) -> AsyncIterator[SSEvent[str]]:
    if request_headers.last_event_id:
        yield SSEvent(f'starting from {request_headers.last_event_id}')
    else:
        yield SSEvent('starting from scratch')


@sse(MsgspecSerializer, headers=Headers[HeaderModel])
async def user_events(
    request: HttpRequest,
    context: SSEContext[None, None, HeaderModel],
) -> SSEResponse[SSEvent[str]]:
    return SSEResponse(produce_user_events(context.parsed_headers))

To:

from collections.abc import AsyncIterator

import msgspec

from dmr.components import Headers
from dmr.plugins.msgspec import MsgspecSerializer
from dmr.streaming.sse import SSEController, SSEvent


class HeaderModel(msgspec.Struct):
    last_event_id: int | None = msgspec.field(
        default=None,
        name='Last-Event-ID',
    )


class UserEventsController(SSEController[MsgspecSerializer]):
    def get(
        self,
        parsed_headers: Headers[HeaderModel],
    ) -> AsyncIterator[SSEvent[str]]:
        return self.produce_user_events(parsed_headers)

    async def produce_user_events(
        self,
        parsed_headers: HeaderModel,
    ) -> AsyncIterator[SSEvent[str]]:
        if parsed_headers.last_event_id is None:
            yield SSEvent('starting from scratch')
        else:
            yield SSEvent(f'starting from {parsed_headers.last_event_id}')
  1. Replace old dmr.sse imports with new dmr.streaming.sse alternatives

Features

  • Added @attrs.define official support, #706
  • Added msgpack parser and renderer, #630
  • Added JsonLines or JsonL support, #607
  • Added ping events to SSE streaming, #606
  • Added SSE support for non-GET methods, Body component parsing, #736
  • Added i18n support for user-facing error messages
    using Django's gettext_lazy, #426
  • Added MediaType validation for the default encoding field
    and OpenAPI 3.2 itemEncoding and prefixEncoding fields, #695
  • Added MediaTypeMetadata metadata item to set required parameters
    for the MediaType request body
    for Body and FileMedata components, #695 and #698
  • Added support for Swagger, Redoc, and Scalar CDN configuration, #678
  • Added TraceCov integration for API coverage tracking in test suites,
    including automatic request tracking for dmr_client and
    dmr_async_client, #735.
  • Added Stoplight Elements UI for OpenAPI documentation, #748

Bugfixes

  • Fixed SSE controllers __name__ and __doc__ generation
    via @sse decorator, #700
  • Fixed a bug where FileMetadata rendered list of schemas incorrectly, #698
  • Fixed that we were using typing.get_type_hints in some places,
    now always using typing_extensions.get_type_hints, #768

Misc

  • Added $dmr-openapi-skeleton AI agent skill, #693
  • Added $dmr-from-django-ninja AI agent skill, #693
  • Added $dmr-from-drf AI agent skill, #744
  • Added ETag usage docs, #699
  • Added multiple translations for the user-facing error messages, #718
  • Now MsgspecJsonRenderer and JsonRenderer produce
    the same json string in terms of whitespaces, #736

New Contributors

Full Changelog: 0.3.0...0.4.0

Version 0.3.0

17 Mar 18:33
e72ce4e

Choose a tag to compare

What's Changed

Features

  • Added FileResponseSpec and improved FileResponse
    schema generation, #682
  • Added encoding: support for file media types in FileMetadata, #682

Bugfixes

  • Fixed OpenAPI schema for custom HTTP Basic auth headers, #672
  • Fixed JWT claim validation and error handling in JWToken.decode, #675
  • Fixed incorrect OpenAPI schema for FileResponse, #682
  • Fixed that 404 was not listed in the endpoint's metadata,
    when using URLRoute without Path component, #685
  • Fixed that 404 was not documented in the OpenAPI
    when Path component was not used, but URLPattern had parameters, #685
  • Fixed ValueError on operation id generation, #685

Misc

  • Improved "Returning responses" docs, #684

New Contributors

Full Changelog: 0.2.0...0.3.0

Version 0.2.0

15 Mar 18:50
f16d60d

Choose a tag to compare

What's Changed

Features

  • Breaking: Renamed schema_only parameter to skip_validation
  • Added dmr.routing.build_500_handler handler, #661
  • Added support for __dmr_split_commas__ in Headers component, #659
  • Added support for native Django urls to be rendered in the OpenAPI,
    now OpenAPI parameters will be generated even without Path component, #659
  • Do not allow '\x00', \n, and \r
    as SSEvent.id and SSEvent.event, #667

Bugfixes

  • Fixes how SSEResponseSpec.headers['Connection'] header is specified, #654
  • Fixed an operation_id generation bug, #652
  • Fixed a bug with parameter schemas were registered with no uses in the OpenAPI
  • Fixed a bug, when request to a missing page with wrong Accept header
    was raising an error. Now it returns 406 as it should, #656
  • Fixed fake examples generation, #638
  • Fixed OpenAPI schema for custom JWT auth parameters, #660
  • Fixed Body component was not able to properly parse lists
    with multipart/form-data parser, #644
  • Fixed that not options were passed to JWToken._build_options, #671

Misc

  • Improved components and auth docs

New Contributors

Full Changelog: 0.1.0...0.2.0

Version 0.1.0 – First public release!

13 Mar 09:42
d36c71b

Choose a tag to compare

django-modern-rest

Modern REST framework with types and async support!

Learn: https://django-modern-rest.readthedocs.io
Download: https://pypi.org/project/django-modern-rest

Contributors

Full Changelog: https://github.com/wemake-services/django-modern-rest/commits/0.1.0