TLDR: Pydantic BaseModel refactor for pydynox
Problem. Two ways to declare a DynamoDB model today, each missing what the other has:
Subclass Model → full DynamoDB features, but no Pydantic (Field(description=...), validators, JSON schema).
@dynamodb_model decorator → real BaseModel, but loses aliases, templates, indexes, hooks, encryption, TTL, version, discriminator, atomic ops, conditions, ModelConfig.
Solution. Make Model itself a pydantic.BaseModel subclass. Keep all existing Attribute classes as the internal runtime representation. Users declare fields Pydantic-style with Annotated[T, Dynamo.*] markers.
Two things to know up front:
Pydantic reserves model_config → pydynox config moves to dynamodb_config: ClassVar[DynamoConfig].
Only breaking change: User.pk == "x" → User.F.pk == "x" (one-release shim provided).
Everything else survives unchanged because GSI/LSI, transactions, batch, hooks, metrics, create_table, etc. all read class dunders (_attributes, _py_to_dynamo, _indexes), not the descriptor protocol.
Where to read more
Decision: ADR/021-pydantic-base-model.md
Deep dive (diagrams, feature matrix, risks): docs/refactor/pydantic-model/overview.md
Per-PR specs: docs/refactor/pydantic-model/ (01- through 05-)
TLDR: Pydantic BaseModel refactor for pydynox
Problem. Two ways to declare a DynamoDB model today, each missing what the other has:
Subclass
Model→ full DynamoDB features, but no Pydantic (Field(description=...), validators, JSON schema).@dynamodb_modeldecorator → realBaseModel, but loses aliases, templates, indexes, hooks, encryption, TTL, version, discriminator, atomic ops, conditions,ModelConfig.Solution. Make
Modelitself apydantic.BaseModelsubclass. Keep all existingAttributeclasses as the internal runtime representation. Users declare fields Pydantic-style withAnnotated[T, Dynamo.*]markers.Two things to know up front:
Pydantic reserves
model_config→ pydynox config moves todynamodb_config: ClassVar[DynamoConfig].Only breaking change:
User.pk == "x"→User.F.pk == "x"(one-release shim provided).Everything else survives unchanged because GSI/LSI, transactions, batch, hooks, metrics,
create_table, etc. all read class dunders (_attributes,_py_to_dynamo,_indexes), not the descriptor protocol.Where to read more
Decision: ADR/021-pydantic-base-model.md
Deep dive (diagrams, feature matrix, risks): docs/refactor/pydantic-model/overview.md
Per-PR specs: docs/refactor/pydantic-model/ (01- through 05-)