Configuration¶
We use DMR_SETTINGS dictionary object to store all the configuration.
All keys are typed with Settings enum keys
which can be used to both set and get settings.
Note
Remember, that django-modern-rest settings
are cached after the first access.
If you need to modify settings dynamically
in runtime use clear_settings_cache().
You can modify the size of cache with adjusting
DMR_MAX_CACHE_SIZE value.
Here are all keys and values that can be set.
As usual, all settings go to settings.py file in your Django project.
See also
Official Django settings docs: https://docs.djangoproject.com/en/5.2/topics/settings
django-split-settingsconfiguration helper https://github.com/wemake-services/django-split-settings
We also validate defined settings in import time. See Settings validation for more details.
Settings¶
Class that can be used to properly type settings in user’s code:
Class with all possible setting keys as enum:
- final class dmr.settings.Settings(*values)[source]¶
Bases:
StrEnumKeys for all settings.
To get settings use
resolve_setting()function together withSettingskeys:>>> from dmr.settings import Settings, resolve_setting >>> resolve_setting(Settings.responses) []
To set settings use:
>>> DMR_SETTINGS = {Settings.responses: []}
Content negotiation¶
Note
It is recommended to always install msgspec
with 'django-modern-rest[msgspec]' extra for better performance.
- dmr.settings.Settings.parsers¶
Default:
dmr.parsers.JsonParserordmr.plugins.msgspec.MsgspecJsonParserif installed.A list of instances of subtypes of
Parserto serialize data from the requested text format, like json or xml, into python object.By default uses
jsonmodule for deserialization ifmsgspecis not installed. And usesmsgspec.jsonifmsgspecis installed.Custom configuration example, let’s say you want to always use
ujson:settings.py¶>>> from dmr.parsers import JsonParser >>> DMR_SETTINGS = {Settings.parsers: [JsonParser()]}
- dmr.settings.Settings.renderers¶
Default:
dmr.renderers.JsonRendererordmr.plugins.msgspec.MsgspecJsonRendererif installed.A list of instances of subtypes of
Rendererto serialize python objects to the requested text format, like json or xml.By default uses
jsonmodule for serialization ifmsgspecis not installed. And usesmsgspec.jsonifmsgspecis installed which are faster.Custom configuration example, let’s say you want to always use
ujson:settings.py¶>>> from dmr.renderers import JsonRenderer >>> DMR_SETTINGS = {Settings.renderers: [JsonRenderer()]}
Response handling¶
- dmr.settings.Settings.responses¶
Default:
[]The list of global
ResponseSpecobject that will be added to all endpoints’ metadata as a possible response schema.Use it to set global responses’ status codes like
500:settings.py¶>>> from http import HTTPStatus >>> from typing_extensions import TypedDict >>> from dmr import ResponseSpec >>> class Error(TypedDict): ... detail: str >>> # If our API can always return a 500 response with `{"detail": str}` >>> # error message: >>> DMR_SETTINGS = { ... Settings.responses: [ ... ResponseSpec( ... Error, ... status_code=HTTPStatus.INTERNAL_SERVER_ERROR, ... ), ... ], ... }
- dmr.settings.Settings.validate_responses¶
Default:
TrueWhen some endpoint returns any data, we by default validate that this data matches the endpoint schema.
So, this code will produce not only static typing error, but also a runtime error:
>>> from dmr import Controller >>> from dmr.plugins.pydantic import PydanticSerializer >>> class MyController(Controller[PydanticSerializer]): ... def get(self) -> list[str]: ... return [1, 2] # <- both static typing and runtime error
But, there’s a runtime cost to this. It is recommended to switch this validation off for production:
settings.py¶>>> DMR_SETTINGS = {Settings.validate_responses: False}Note
You can also switch off this validation per-controller with
validate_responsesand per-endpoint withvalidate_responsesargument tomodify()andvalidate().
- dmr.settings.Settings.semantic_responses¶
Default:
TrueWhen
True, parsers, renderers, and authentication classes automatically inject their semantic response specs (e.g.422 Unprocessable Entity,406 Not Acceptable) into every endpoint’s metadata. These responses are then visible in the generated OpenAPI spec.Set to
Falseto disable this auto-injection globally. User-defined responses (via@modify,@validate, controllerresponses, orSettings.responses) are not affected by this flag. Runtime response validation still works as configured bySettings.validate_responses.settings.py¶>>> DMR_SETTINGS = {Settings.semantic_responses: False}
Error handling¶
- dmr.settings.Settings.global_error_handler¶
Default:
'dmr.errors.global_error_handler'Globally handle all errors in the application. You can use real object or string path for the object to be imported. Here’s our error handling hieracy:
Per-endpoint with
handle_error()andhandle_async_error()Per-controller with
handle_error()orhandle_async_error()If nothing helped,
'global_error_handler'is called
See
global_error_handler()for the callback type.settings.py¶>>> DMR_SETTINGS = {Settings.global_error_handler: 'path.to.your.handler'}
Authentication¶
- dmr.settings.Settings.auth¶
Default:
[]Configure authentication rules for the whole API.
To enable auth for all endpoints you can use:
settings.py¶>>> from dmr.security.django_session import DjangoSessionSyncAuth >>> DMR_SETTINGS = { ... Settings.auth: [ ... DjangoSessionSyncAuth(), ... ], ... }
All auth types must be importable in settings.
Note
All auth classes must support initialization without parameters.
HTTP Spec validation¶
- dmr.settings.Settings.no_validate_http_spec¶
Default:
frozenset()A set of unique
HttpSpeccodes to be globally disabled.We don’t recommend disabling any of these checks globally.
settings.py¶>>> from dmr.settings import HttpSpec >>> DMR_SETTINGS = { ... Settings.no_validate_http_spec: { ... HttpSpec.empty_request_body, ... }, ... }
- final class dmr.settings.HttpSpec(*values)[source]¶
Bases:
StrEnumKeys for our HTTP spec validation.
All rules can be disabled per endpoint and per controller. You can disable any of the validation rules we have here globally by:
>>> DMR_SETTINGS = { ... Settings.no_validate_http_spec: { ... HttpSpec.empty_response_body, ... }, ... }
- empty_request_body¶
Disables validation that methods like
GETandHEADcan’t have request bodies.
- empty_response_body¶
Disables validation that some status codes like
204must not have response bodies.
Streaming¶
- dmr.settings.Settings.validate_events¶
Default:
NoneShould we validate the events in all streams? Defaults to the value set in
validate_responsesfor convenience if this value isNone.To disable the event validation globally, use:
settings.py¶>>> DMR_SETTINGS = { ... Settings.validate_events: False, ... }
OpenAPI¶
- dmr.settings.Settings.openapi_config¶
Default:
OpenAPIConfig(title='Django Modern Rest', version='0.1.0')Metadata to be used in the OpenAPI schema.
See
OpenAPIConfigfor the available fields and their description. It can also be used to change the default OpenAPI spec version.settings.py¶>>> from dmr.openapi.config import OpenAPIConfig >>> DMR_SETTINGS = { ... Settings.openapi_config: OpenAPIConfig( ... title='My Amazing App', ... version='13.22.3', ... openapi_version='3.2.0', ... ), ... }
- dmr.settings.Settings.openapi_examples_seed¶
Default:
NoneRandom seed to use when generating missing examples in the OpenAPI spec.
If set to
None, no examples are generated. Existing examples won’t be overridden.It only works if
'django-modern-rest[openapi]'extra is installed. If polyfactory package is missing, no examples are generated.settings.py¶>>> from dmr.settings import HttpSpec >>> from dmr.openapi.config import OpenAPIConfig >>> DMR_SETTINGS = { ... Settings.openapi_examples_seed: 10, ... }
- dmr.settings.Settings.openapi_static_cdn¶
Default:
{}Optional mapping to switch OpenAPI renderers to CDN resources. Only renderers explicitly listed in this mapping will use CDN, the rest will use local bundled static files served by Django.
Supported keys are:
swagger: base URL toswagger-ui-dist(without file name)redoc: full URL toredoc.standalone.jsscalar: full URL to@scalar/api-referencestandalone bundlestoplight: base URL to@stoplight/elements(without file name)
You can also modify the exact versions that we use for each tool this way.
settings.py¶>>> DMR_SETTINGS = { ... Settings.openapi_static_cdn: { ... 'swagger': 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.32.1', ... 'redoc': 'https://cdn.redoc.ly/redoc/2.5.2/bundles/redoc.standalone.js', ... 'scalar': 'https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.49.2/dist/browser/standalone.js', ... 'stoplight': 'https://unpkg.com/@stoplight/elements@9.0.16', ... }, ... }
Hacks¶
- dmr.settings.Settings.django_treat_as_post¶
Default:
frozenset({'PUT', 'PATCH'})By default Django only populates
django.http.HttpRequest.POSTanddjango.http.HttpRequest.FILESforPOSTrequests.Some parsers like
MultiPartParserrequire.POSTand.FILESto be set to work withBodyandFileMetadata.However, we build REST APIs where more methods are in use, not just
POST. So, we use this setting to populate.POSTand.FILESwhen parser is a subtype of eitherSupportsFileParsingorSupportsDjangoDefaultParsingand we work with components that require request body.Note
This is a really advanced setting. If you are not creating your own components or your own parsers - do not change it.
Environment variables¶
- DMR_MAX_CACHE_SIZE¶
Default:
256We use
functools.lru_cache()in many places internally. For example:To create json encoders and decoders only once
To create type validation objects in
BaseEndpointOptimizer
You can control the size / memory usage with this setting.
Increase if you have a lot of different return types.
API Reference¶
- dmr.settings.resolve_setting(setting_name: Settings, *, import_string: bool = False) Any[source]¶
Resolves setting by setting_name.
The result is cached using
@lru_cachefor performance. When testing with custom settings, you must callclear_settings_cache()before and after modifying Django settings to ensure the cache is invalidated properly.