ModelSerializer¶
ModelSerializer is a Django model base class that carries its own schemas,
Python CRUD methods and hooks. For how to use it, see
Schemas and Python CRUD.
from ninja_aio import ModelSerializer, SchemaConfig
Schemas¶
Declare each kind with a SchemaConfig inside class Schemas:. The generated
names below are for a model named Article.
| Kind | Schema attribute | Generated name | Used for |
|---|---|---|---|
create |
create_schema |
articleSchemaIn |
Create request body |
update |
update_schema |
articleSchemaPatch |
Update request body |
read |
read_schema |
articleSchemaOut |
List, create and update responses |
detail |
detail_schema |
articleDetailSchemaOut |
Retrieve response. Falls back to read |
| (automatic) | related_schema |
articleSchemaRelated |
This model nested inside another model |
class Article(ModelSerializer):
...
class Schemas:
create = SchemaConfig(fields=["title", "body", "category"])
update = SchemaConfig(optionals=[("title", str), ("body", str)])
read = SchemaConfig(fields=["id", "title", "category"])
A kind you leave out has no schema (None), and its endpoint is not generated.
See Schema generation for how fields become
schemas.
Validators¶
Put Pydantic @field_validator and @model_validator methods on these inner
classes:
| Inner class | Applies to |
|---|---|
CreateValidators |
create schema |
UpdateValidators |
update schema |
ReadValidators |
read schema |
DetailValidators |
detail schema |
Schema attributes¶
| Attribute | Description |
|---|---|
create_schema, update_schema, read_schema, detail_schema, related_schema |
The generated schema class, or None if the kind is not declared. Built on first access and cached |
get_schema(kind, *, depth=1) |
Returns the schema for "create", "update", "read", "detail" or "related". depth (relation nesting) only applies to read and detail |
clear_schema_cache() |
Drops the cached schemas of this class |
Assign your own Schema subclass to an attribute, for example
read_schema = ArticleOut, to replace the generated one.
Python methods¶
All methods are classmethods. request is keyword-only and optional in every
method.
| Sync | Async | Returns |
|---|---|---|
create(data, *, request=None) |
acreate(...) |
Article |
get(pk=None, *, request=None, optimize_for=None, **lookups) |
aget(...) |
Article |
get_queryset(*, request=None, optimize_for=None) |
aget_queryset(...) |
QuerySet[Article] |
update(target, data, *, request=None) |
aupdate(...) |
Article |
destroy(target, *, request=None) |
adestroy(...) |
None |
model_dump(instance, *, schema=None, strict=False) |
amodel_dump(instance, *, schema=None) |
dict (default: detail schema) |
model_dumps(instances, *, schema=None, strict=False) |
amodel_dumps(instances, *, schema=None) |
list[dict] (default: read schema) |
bulk_create(items, *, request=None) |
abulk_create(...) |
BulkResult[Article] |
bulk_update(items, *, request=None) |
abulk_update(...) |
BulkResult[Article] |
bulk_destroy(targets, *, request=None) |
abulk_destroy(...) |
BulkResult of primary keys |
target is an instance or a primary key. optimize_for is "read" or
"detail". The dump methods load missing relations with one query per
relation. strict=True makes the sync dump raise ValueError instead of
running any query.
create
classmethod
¶
create(data: InputData, *, request: HttpRequest | None = None) -> ModelSerializerT
Create and return one model instance synchronously.
acreate
async
classmethod
¶
acreate(data: InputData, *, request: HttpRequest | None = None) -> ModelSerializerT
Create and return one model instance asynchronously.
get
classmethod
¶
get(pk: PrimaryKey | None = None, *, request: HttpRequest | None = None, optimize_for: QueryPurpose | None = None, **lookups: Any) -> ModelSerializerT
Retrieve and return one model instance synchronously.
aget
async
classmethod
¶
aget(pk: PrimaryKey | None = None, *, request: HttpRequest | None = None, optimize_for: QueryPurpose | None = None, **lookups: Any) -> ModelSerializerT
Retrieve and return one model instance asynchronously.
update
classmethod
¶
update(target: ModelSerializerT | PrimaryKey, data: InputData, *, request: HttpRequest | None = None) -> ModelSerializerT
Update and return one model instance synchronously.
aupdate
async
classmethod
¶
aupdate(target: ModelSerializerT | PrimaryKey, data: InputData, *, request: HttpRequest | None = None) -> ModelSerializerT
Update and return one model instance asynchronously.
destroy
classmethod
¶
destroy(target: ModelSerializerT | PrimaryKey, *, request: HttpRequest | None = None) -> None
Destroy one model instance synchronously.
adestroy
async
classmethod
¶
adestroy(target: ModelSerializerT | PrimaryKey, *, request: HttpRequest | None = None) -> None
Destroy one model instance asynchronously.
model_dump
classmethod
¶
model_dump(instance: ModelSerializerT, *, schema: SchemaType | None = None, strict: bool = False) -> dict[str, Any]
Serialize one instance, loading missing schema relations; strict=True never queries.
amodel_dump
async
classmethod
¶
amodel_dump(instance: ModelSerializerT, *, schema: SchemaType | None = None) -> dict[str, Any]
Serialize one instance, loading relations required by the schema.
model_dumps
classmethod
¶
model_dumps(instances: Iterable[ModelSerializerT] | QuerySet[ModelSerializerT], *, schema: SchemaType | None = None, strict: bool = False) -> list[dict[str, Any]]
Serialize a collection with the read schema, one query per missing relation.
amodel_dumps
async
classmethod
¶
amodel_dumps(instances: Iterable[ModelSerializerT] | QuerySet[ModelSerializerT], *, schema: SchemaType | None = None) -> list[dict[str, Any]]
Serialize instances, loading relations required by the read schema.
Hooks¶
Sync viewsets call the plain names, async viewsets the a names. Override one
of the pair. See Hooks.
| Hook | Signature | Runs |
|---|---|---|
queryset_request / aqueryset_request |
(cls, request) classmethod |
Builds the base queryset for lookups, lists, updates and deletes |
post_create / apost_create |
(self) |
Once, after the object is created |
custom_actions / acustom_actions |
(self, payload) |
On create and update, with the customs fields as a dict |
on_create_before_save |
(self) |
Before the first save only |
before_save |
(self) |
Before every save |
on_create_after_save |
(self) |
After the first save only |
after_save |
(self) |
After every save |
on_delete |
(self) |
After the object is deleted |
has_changed / ahas_changed |
(self, field) -> bool |
Helper: True if the value differs from the database |
as_admin |
(cls, **overrides) -> type |
Helper: returns a Django ModelAdmin class built from the schemas |
Query optimization¶
Declare class QuerySet: on the model to add select_related and
prefetch_related to generated queries.
| Attribute | Type | Description |
|---|---|---|
read, detail, queryset_request, extras |
ModelQuerySetSchema (extras: list of ModelQuerySetExtraSchema) |
Relations to load for list, retrieve and the base queryset. detail falls back to read. extras adds named scopes |
from ninja_aio.schemas import ModelQuerySetSchema
class Article(ModelSerializer):
...
class QuerySet:
read = ModelQuerySetSchema(select_related=["category"])
NinjaAIOMeta¶
Optional inner class with names the framework uses instead of Django's Meta.
| Key | Default | Description |
|---|---|---|
verbose_name |
Meta.verbose_name |
Singular name, used in the OpenAPI tag |
verbose_name_plural |
Meta.verbose_name_plural |
Plural name. Spaces become hyphens in the default URL path |
not_found_name |
Model name | Error text of 404 responses: {"error": "<not_found_name>"} |
class Article(ModelSerializer):
...
class NinjaAIOMeta:
verbose_name_plural = "blog posts" # -> /api/blog-posts