Tutorial¶
Defining a model¶
Schemap supports three approaches. All three produce identical schemas. Pick the one that fits your project.
AutoBase — inherit from the ready-made declarative base:
from schemap import AutoBase
from sqlalchemy.orm import Mapped, mapped_column
class Product(AutoBase):
__tablename__ = "products"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
price: Mapped[float] = mapped_column(nullable=True)
SchemaMixin — use with an existing custom declarative base:
from schemap import SchemaMixin
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(SchemaMixin, DeclarativeBase):
pass
class Product(Base):
__tablename__ = "products"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
@auto_schema — decorate any model without changing its base class:
from schemap import auto_schema
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
@auto_schema
class Product(Base):
__tablename__ = "products"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
# With configuration
@auto_schema(config=SchemaConfig(exclude_public=["price"]))
class Product(Base):
...
State of .gitignore¶
Make sure .gitignore excludes site/ (the zensical build output) alongside the usual Python entries:
Schema variants¶
| Variant | What it excludes |
|---|---|
.Schema |
Nothing |
.CreateSchema |
Primary keys, server_defaults, client defaults |
.UpdateSchema |
Primary keys (all fields become Optional with None) |
.PublicSchema |
Columns starting with __ |
Converting between ORM and schemas¶
# ORM instance to schema
user = User(id=1, name="Alice")
schema = user.to_schema()
schema = user.to_schema(User.PublicSchema) # Specific variant
# Schema to ORM instance
data = User.CreateSchema(name="Bob")
user = User.from_schema(data)
Customizing schemas¶
Attach SchemaConfig to any model with __schema_config__:
from schemap import AutoBase, SchemaConfig
class User(AutoBase):
__tablename__ = "users"
__schema_config__ = SchemaConfig(
exclude_public=["email", "phone"],
)
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
email: Mapped[str]
phone: Mapped[str]
SchemaConfig options¶
exclude_always: list[str]-- Excluded from all schemas.exclude_create: list[str]-- Excluded from CreateSchema only.exclude_update: list[str]-- Excluded from UpdateSchema only.exclude_public: list[str]-- Excluded from PublicSchema only.field_overrides: dict[str, Any]-- Override a field's Python type.required_always: list[str]-- Force fields to be required.optional_always: list[str]-- Force fields to be optional.extra_validators: dict[str, Callable]-- Custom validators per field.
Custom validators¶
def must_be_positive(v: float) -> float:
if v <= 0:
raise ValueError("Must be positive")
return v
SchemaConfig(extra_validators={"price": must_be_positive})
Invalid values raise pydantic.ValidationError.