Getting started#
Installation#
Works for:
CPython 3.11+ or PyPy 3.11+
Django 5.0+
uv add django-modern-rest
poetry add django-modern-rest
pip install django-modern-rest
Extras for different serializers:
'django-modern-rest[pydantic]'forpydanticsupport'django-modern-rest[attrs]'forattrssupport'django-modern-rest[msgspec]'formsgspecsupport and the fastestjsonparsing in requests,jwt, testing, and OpenAPI
Extras for different features:
'django-modern-rest[jwt]'for jwt support'django-modern-rest[openapi]'for OpenAPI schema validation and better example generation
Important
We highly recommend always installing
msgspec, even when using just
pydantic for APIs.
We use msgspec to parse json when it is available
because it is the fastest
library out there for this task.
We also recommend always installing django-stubs for typing Django itself.
Note
You don’t need to add 'dmr' to INSTALLED_APPS
unless you want to serve static files for OpenAPI.
LLMs support#
Are you using AI for assisted coding? We’ve got you covered. Use these files for context to make sure that the LLM knows our framework:
https://django-modern-rest.readthedocs.io/llms.txt for indexes with links to different pages and topics
https://django-modern-rest.readthedocs.io/llms-full.txt for complete docs
Every documentation page is also served as Markdown, replace
.htmlwith.mdin its URL, or pressM↓next to the title of any page
We also support Context7 for up-to-date docs for LLMs.
Use cases we officially support:
Learning
django-modern-restwith the help of DeepWikiAI-guided migrations for any API changes. Did we break something? Every breaking release ships a migration prompt, so you can upgrade to a newer version using an AI tool of your choice
We ship several agent skills inside the package, install them into your project with a single command:
uvx library-skills
$dmrto enforcedjango-modern-restbest practices with fast and secure approaches$dmr-upgradeto upgrade to a newer release with the official migration prompts$dmr-openapi-skeletonto generate a working project boilerplate from a singleopenapi.jsonfile (the “Spec First” approach)$dmr-from-django-ninjato help with migrating from Django Ninja$dmr-from-drfto help with migrating from Django REST Framework$dmr-from-dj-rest-authto help with migrating from dj-rest-auth
Showcase#
Let’s see the basics and learn how to use dmr in a single example:
We support msgspec.Struct
via MsgspecSerializer.
1import uuid
2
3import msgspec
4
5from dmr import Body, Controller
6from dmr.plugins.msgspec import MsgspecSerializer
7
8
9class UserCreateModel(msgspec.Struct):
10 email: str
11
12
13class UserModel(UserCreateModel):
14 uid: uuid.UUID
15
16
17class UserController(Controller[MsgspecSerializer]):
18 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
19 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
20
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"email":"email@example.com","uid":"eaec2882-4897-4afe-839c-dc51454235bc"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"operationId": "postUserControllerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support pydantic.BaseModel
via PydanticSerializer
and PydanticFastSerializer.
Tip
PydanticFastSerializer is faster,
but it only works with json
parsers and renderers.
If you need other formats, use
PydanticSerializer instead.
1import uuid
2
3import pydantic
4
5from dmr import Body, Controller
6from dmr.plugins.pydantic import PydanticFastSerializer
7
8
9class UserCreateModel(pydantic.BaseModel):
10 email: str
11
12
13class UserModel(UserCreateModel):
14 uid: uuid.UUID
15
16
17class UserController(Controller[PydanticFastSerializer]):
18 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
19 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
20
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"email":"email@example.com","uid":"24b610fd-dacd-4c2e-a178-a29b751b3944"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
},
"uid": {
"format": "uuid",
"title": "Uid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"operationId": "postUserControllerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support attrs.define()
via MsgspecSerializer.
See msgspec docs
on attrs support.
1import uuid
2
3import attrs
4
5from dmr import Body, Controller
6from dmr.plugins.msgspec import MsgspecSerializer
7
8
9@attrs.define
10class UserCreateModel:
11 email: str
12
13
14@attrs.define
15class UserModel(UserCreateModel):
16 uid: uuid.UUID
17
18
19class UserController(Controller[MsgspecSerializer]):
20 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
21 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
22
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"uid":"b1874b4a-22d2-456a-b488-60a05f3c7943","email":"email@example.com"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"operationId": "postUserControllerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support dataclasses.dataclass() via both
MsgspecSerializer
and PydanticSerializer.
1import dataclasses
2import uuid
3
4from dmr import Body, Controller
5from dmr.plugins.msgspec import MsgspecSerializer
6
7
8@dataclasses.dataclass
9class UserCreateModel:
10 email: str
11
12
13@dataclasses.dataclass
14class UserModel(UserCreateModel):
15 uid: uuid.UUID
16
17
18class UserController(Controller[MsgspecSerializer]):
19 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
20 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
21
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"email":"email@example.com","uid":"f6d22fb8-70b4-48c3-b7ca-3ec4af9fd9d3"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"operationId": "postUserControllerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support typing.TypedDict via both
MsgspecSerializer
and PydanticSerializer.
1import uuid
2
3from typing_extensions import TypedDict
4
5from dmr import Body, Controller
6from dmr.plugins.msgspec import MsgspecSerializer
7
8
9class UserCreateModel(TypedDict):
10 email: str
11
12
13class UserModel(UserCreateModel):
14 uid: uuid.UUID
15
16
17class UserController(Controller[MsgspecSerializer]):
18 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
19 return UserModel(uid=uuid.uuid4(), email=parsed_body['email'])
20
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"uid":"d6cead19-4c62-4edb-a5d0-730c6f7f6591","email":"email@example.com"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"operationId": "postUserControllerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support typing.NamedTuple
via PydanticSerializer.
1import uuid
2from typing import NamedTuple
3
4from dmr import Body, Controller
5from dmr.plugins.pydantic import PydanticFastSerializer
6
7
8class UserCreateModel(NamedTuple):
9 email: str
10
11
12class UserModel(NamedTuple):
13 email: str
14 uid: uuid.UUID
15
16
17class UserController(Controller[PydanticFastSerializer]):
18 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
19 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
20
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
["email@example.com","81951252-dbc4-4227-8df9-773e3ed7c687"]
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"operationId": "postUserControllerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"maxItems": 1,
"minItems": 1,
"prefixItems": [
{
"title": "Email",
"type": "string"
}
],
"type": "array"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"maxItems": 2,
"minItems": 2,
"prefixItems": [
{
"title": "Email",
"type": "string"
},
{
"format": "uuid",
"title": "Uid",
"type": "string"
}
],
"type": "array"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
Important
You can choose a serializer per controller, which will give you
the freedom to pick the best serializer and model for the job.
msgspec gives you more speed,
while pydantic gives you more flexibility.
In this example:
We defined regular
pydantic,msgspec, or any other models we will use for our APIWe added a component parser for the request’s
Body, which will parse it into the typed model that we pass to this component as a type parameterNext, we created a
Controllerclass withPydanticSerializerorMsgspecSerializerto serialize input and output data for usWe also defined a
postAPI endpoint and returned a simple model response from it. It will be automatically transformed into adjango.http.HttpResponseinstance bydjango-modern-rest
Now, let’s add our controller to the list of URLs:
1# Our `path` is an optimized drop-in replacement of `django.urls.path`:
2from dmr.routing import Router, path
3from examples.getting_started.pydantic_controller import UserController
4
5# Router is just a collection of regular Django urls:
6router = Router(
7 'api/',
8 [
9 path(
10 'user/',
11 UserController.as_view(),
12 name='users',
13 ),
14 ],
15)
16
17# Just a regular `urlpatterns` definition, Django-style:
18urlpatterns = [
19 router.to_urlpatterns(namespace='api'),
20]
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "user@wms.org"}' -H 'Content-Type: application/json'
{"email":"user@wms.org","uid":"9e138f7d-2906-4c6c-923f-0f016d6cc272"}
Your first django-modern-rest API is ready.
Next, you can learn:
How to generate an OpenAPI schema
How to handle errors
How to customize controllers and endpoints
Full example#
If you were ever told that Django is too big and complicated, that was misleading, to say the least.
Here’s a single-file application that looks pretty much the same as any other micro-framework, like FastAPI, Litestar, or Flask.
1import secrets
2import sys
3import uuid
4
5import pydantic
6from django.conf import settings
7from django.core.management import execute_from_command_line
8
9from dmr import Body, Controller
10from dmr.openapi import build_schema
11from dmr.openapi.views import OpenAPIJsonView, SwaggerView
12from dmr.plugins.pydantic import PydanticFastSerializer
13from dmr.routing import Router, path
14
15if not settings.configured:
16 settings.configure(
17 ROOT_URLCONF=__name__,
18 ALLOWED_HOSTS='*',
19 DEBUG=True,
20 INSTALLED_APPS=['dmr', 'django.contrib.staticfiles'],
21 STATIC_URL='/static/',
22 STATICFILES_FINDERS=[
23 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
24 ],
25 TEMPLATES=[
26 {
27 'APP_DIRS': True,
28 'BACKEND': 'django.template.backends.django.DjangoTemplates',
29 },
30 ],
31 # Secret key for tests, will be new on each run,
32 # in production it must be the same token, kept in secret:
33 SECRET_KEY=secrets.token_hex(),
34 )
35
36
37class UserCreateModel(pydantic.BaseModel):
38 email: str
39
40
41class UserResponseModel(UserCreateModel):
42 uid: uuid.UUID
43
44
45class UserController(Controller[PydanticFastSerializer]):
46 async def post(
47 self,
48 parsed_body: Body[UserCreateModel],
49 ) -> UserResponseModel:
50 return UserResponseModel(uid=uuid.uuid4(), email=parsed_body.email)
51
52
53router = Router(
54 'api/',
55 [
56 path('user/', UserController.as_view(), name='users'),
57 ],
58)
59schema = build_schema(router)
60
61urlpatterns = [
62 router.to_urlpatterns(namespace='api'),
63 path('docs/openapi.json/', OpenAPIJsonView.as_view(schema), name='openapi'),
64 path('docs/swagger/', SwaggerView.as_view(schema), name='swagger'),
65]
66
67if __name__ == '__main__':
68 # Use `python THIS_FILE_NAME.py runserver` to run the example.
69 # Then visit `http://localhost:8000/docs/swagger` to view the docs.
70 execute_from_command_line(sys.argv)
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "djangomodernrest@wemake.services"}' -H 'Content-Type: application/json'
{"email":"djangomodernrest@wemake.services","uid":"ef5ed1c1-876a-4447-bd47-326b9455ff95"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserResponseModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
},
"uid": {
"format": "uuid",
"title": "Uid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserResponseModel",
"type": "object"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/user/": {
"post": {
"operationId": "postUserControllerApiUser",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserResponseModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
You can copy it by clicking “Copy” in the upper-right corner of the example.
The copy button appears when you hover over the code example. Paste it as example.py,
install django-modern-rest, and run it with:
uv run python example.py runserver
poetry run python example.py runserver
python example.py runserver
Your API is now live:
POSThttp://localhost:8000/api/user/ — create a user
Then visit http://localhost:8000/docs/swagger/ for the interactive docs.
That’s it, enjoy your new project!
But this is too simple for my use case!#
What is great about Django is that it scales. You can start with a single-file app and scale it up to a full-featured monolith with strict context boundaries, DDD, reusable apps, etc.
We recommend starting new big projects with https://github.com/wemake-services/wemake-django-template.
It is a strict, security-first, battle-proven, highload-tested boilerplate for real apps of the modern age.
Type checking#
django-modern-rest officially supports all major Python type checkers
in strict mode (listed in order of recommendation):
mypy, which has the best support due to the django-stubs plugin
Installing django-stubs is required for all of them.
Next up#
Learn the fundamentals.
Learn how to configure django-modern-rest.