Django Modern Schemas¶
Declarative Pydantic v2 schemas generated from Django models.
Django Modern Schemas reads a model's field definitions — types, null, blank,
default, choices, max_length — and builds a real Pydantic model from them.
You get validation, serialization and JSON Schema without restating the field
definitions you already wrote in models.py.
Every example on this site is executed
Code blocks written as a console transcript (>>>) are run by the test suite
on every commit, and the output shown is the output the library produced.
See How these docs are tested.
Installation¶
Requires Python 3.10+, Django 3.2+ and Pydantic 2.13+. Nothing needs to be added
to INSTALLED_APPS — the library is imported, not installed as an app.
A first schema¶
Given an ordinary Django model:
class Event(models.Model):
title = models.CharField(max_length=100)
category = models.OneToOneField(Category, null=True, on_delete=models.SET_NULL)
class Meta:
app_label = 'examples'
def display_title(self) -> str:
return f'Event: {self.title}'
Declare a schema that names the model in a nested Config class:
>>> class EventSchema(ModelSchema):
... class Config:
... model = models.Event
... fields = ['id', 'title']
The result is a Pydantic model. It validates a Django instance directly:
>>> event = models.Event(id=1, title='DjangoCon')
>>> EventSchema.model_validate(event).model_dump()
{'id': 1, 'title': 'DjangoCon'}
It reads a JSON payload and writes it back through the ORM:
>>> class EventCreateSchema(ModelSchema):
... class Config:
... model = models.Event
... fields = ['title']
>>> created = EventCreateSchema.model_validate({'title': 'PyCon'}).create()
>>> created.pk is not None
True
Input that the database would reject is refused first, with a Pydantic
ValidationError you can return as a 400.
And it describes itself as JSON Schema:
>>> print(json.dumps(EventSchema.model_json_schema()['properties']['title'], indent=2))
{
"description": "",
"maxLength": 100,
"title": "Title",
"type": "string"
}
max_length=100 on the Django field became maxLength: 100 in the JSON Schema.
Constraints are carried across rather than re-declared.
What you get¶
Generated fields¶
Django field types, null/blank, defaults and choices become Pydantic
annotations. See the field reference.
Explicit relations¶
Relations serialize as primary keys by default, or as nested schemas when you
ask for them with depth. See Relations.
Renamed and computed values¶
Source reads a dotted attribute path; MethodSource calls a model method.
See Source and MethodSource.
Persistence¶
create(), update() and save() write validated data back through the ORM.
See Persistence.
Where to go next¶
| If you want to | Read |
|---|---|
| Understand the pieces and their boundaries | Overview |
| Follow a worked tutorial from an empty app | Getting Started |
Configure fields, exclude, optional, depth |
ModelSchema |
| Look up how a Django field is converted | Field reference |
| Build schemas at runtime | SchemaFactory |
Scope¶
This library builds schemas from models and writes flat data back. It deliberately does not plan queries for you, and it does not perform nested writes. Those boundaries are stated in full under Overview → Boundaries.
Credits¶
Django Modern Schemas is maintained by Open Byte. It builds on the design of Ninja Schema by Tochukwu (@eadwinCode) — see Credits and Stewardship.