SQLAlchemy + Pydantic, one model · by the FastAPI author · verified against SQLModel 0.0.27 (2026)

SQLModel cheat sheet

SQLModel unifies a database table and a Pydantic model into one Python class. Built on SQLAlchemy 2.0 (the engine, sessions, queries) and Pydantic v2 (validation, serialization) by the author of FastAPI, it's the batteries-included ORM for FastAPI apps: type-annotated models, editor autocompletion, and no duplicated schemas. The whole trick is table=True — classes with it are real tables; classes without it are plain data schemas. This sheet targets SQLModel 0.0.27.

define fields query (CRUD) relationships FastAPI & async gotcha most common

Verified 2026-08-24 against the official docs at sqlmodel.tiangolo.com (SQLModel 0.0.27). Requires SQLAlchemy ≥2.0.14,<2.1 and Pydantic ≥1.10.13,<3 (v2 supported). Python 3.12+ fine. For schema migrations pair it with Alembic; create_all never ALTERs existing tables.

Outline

Define a model with table=True, make the engine, then CRUD through a Session using select() + session.exec(). Relationships and the FastAPI multi-model pattern round it out.

Define

  1. 1 · Install & imports
  2. 2 · Define a model
  3. 3 · Field & columns

Query

  1. 4 · Engine, tables & Session
  2. 5 · Create & read
  3. 6 · Update & delete

Relate & ship

  1. 7 · Relationships
  2. 8 · FastAPI & async
  3. 9 · Gotchas
  4. Worth memorizing

Define

One class = one table + one schema. It all hinges on table=True.

1Install & imports0.0.27
2Define a modeltable=True is the switch
3Field & columnsconstraints & indexes

Query

Make the engine and tables once, then do all reads and writes inside a Session.

4Engine, tables & Sessionsetup
5Create & readadd / select / exec
6Update & deletemutate rows

Relate & ship

Link tables, then use the multi-model pattern (and async) for FastAPI.

7Relationshipsnavigate between tables
8FastAPI & asyncmulti-model + AsyncSession
!Common gotchasread before shipping

Worth memorizing

table=True = real tableno flag = plain Pydantic schema
id: int | None = Field(primary_key=True)None until commit + refresh
Field(index / unique / foreign_key)constraints live on the column
create_engine onceSQLModel.metadata.create_all(engine)
with Session(engine) as sessionadd / commit / refresh
session.exec(select(...)).all()exec returns model objects, not Rows
session.get(Model, pk)fastest read by primary key
Relationship(back_populates=...)names must match on both sides
Base + Create/Public/Updatenever expose the table model in FastAPI
AsyncSession + await exec/commitasync driver: aiosqlite / asyncpg
Alembic for migrationscreate_all never ALTERs
SQLAlchemy 2.0 + Pydantic v2 under the hooddrop to sa_column for advanced types