Skip to content

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:

site/
__pycache__/
*.pyc

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.