SQLModel - SQL Databases in Python
What is SQLModel?
SQLModel is a library for interacting with SQL databases from Python code, designed by the creator of
FastAPI. It combines the power of SQLAlchemy with the simplicity of Pydantic, providing type safety and
editor support while maintaining compatibility with both libraries.
Key Features
Type Safety: Full type hints support with mypy compatibility
Pydantic Integration: Seamless data validation and serialization
SQLAlchemy Compatibility: Built on top of SQLAlchemy Core and ORM
FastAPI Integration: Perfect companion for FastAPI applications
Code Reuse: Single model definition for database and API schemas
Modern Python: Designed for Python 3.7+ with dataclasses-like syntax
Installation
pip install sqlmodel
# For async support
pip install sqlmodel[async]
Basic Model Definition
from typing import Optional
from sqlmodel import SQLModel, Field, create_engine, Session, select
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
secret_name: str
age: Optional[int] = Field(default=None, index=True)
team_id: Optional[int] = Field(default=None, foreign_key="[Link]")
Page 1 of 6
class Team(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
headquarters: str
Database Setup
# Create engine
sqlite_file_name = "[Link]"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
# Create tables
def create_db_and_tables():
[Link].create_all(engine)
CRUD Operations
Create
def create_hero():
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
with Session(engine) as session:
[Link](hero_1)
[Link](hero_2)
[Link]()
[Link](hero_1)
[Link](hero_2)
print(f"Created hero: {hero_1}")
Read
def select_heroes():
with Session(engine) as session:
# Select all
Page 2 of 6
statement = select(Hero)
results = [Link](statement)
for hero in results:
print(hero)
# Select with conditions
statement = select(Hero).where([Link] == "Deadpond")
hero = [Link](statement).first()
print(hero)
# Select with limit and offset
statement = select(Hero).offset(0).limit(3)
heroes = [Link](statement).all()
Update
def update_hero():
with Session(engine) as session:
statement = select(Hero).where([Link] == "Spider-Boy")
hero = [Link](statement).one()
[Link] = 16
[Link](hero)
[Link]()
[Link](hero)
print(f"Updated hero: {hero}")
Delete
def delete_hero():
with Session(engine) as session:
statement = select(Hero).where([Link] == "Spider-Boy")
hero = [Link](statement).one()
[Link](hero)
[Link]()
Relationships
from typing import List
from sqlmodel import Relationship
Page 3 of 6
class Team(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
headquarters: str
heroes: List["Hero"] = Relationship(back_populates="team")
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
secret_name: str
age: Optional[int] = Field(default=None, index=True)
team_id: Optional[int] = Field(default=None, foreign_key="[Link]")
team: Optional[Team] = Relationship(back_populates="heroes")
# Query with relationships
def select_heroes_with_team():
with Session(engine) as session:
statement = select(Hero, Team).where(Hero.team_id == [Link])
results = [Link](statement)
for hero, team in results:
print(f"Hero: {[Link]}, Team: {[Link]}")
FastAPI Integration
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
def get_session():
with Session(engine) as session:
yield session
@[Link]("/heroes/", response_model=Hero)
def create_hero(hero: Hero, session: Session = Depends(get_session)):
[Link](hero)
[Link]()
[Link](hero)
return hero
Page 4 of 6
@[Link]("/heroes/", response_model=List[Hero])
def read_heroes(
offset: int = 0,
limit: int = Query(default=100, lte=100),
session: Session = Depends(get_session)
):
heroes = [Link](select(Hero).offset(offset).limit(limit)).all()
return heroes
@[Link]("/heroes/{hero_id}", response_model=Hero)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = [Link](Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero
Advanced Features
Multiple Models from Same Table
class HeroBase(SQLModel):
name: str = Field(index=True)
secret_name: str
age: Optional[int] = Field(default=None, index=True)
class Hero(HeroBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
class HeroCreate(HeroBase):
pass
class HeroRead(HeroBase):
id: int
class HeroUpdate(SQLModel):
name: Optional[str] = None
secret_name: Optional[str] = None
age: Optional[int] = None
Async Support
Page 5 of 6
from [Link] import create_async_engine, AsyncSession
from [Link] import AsyncSession
async_engine = create_async_engine("sqlite+aiosqlite:///./[Link]")
async def create_hero_async():
async with AsyncSession(async_engine) as session:
hero = Hero(name="Deadpond", secret_name="Dive Wilson")
[Link](hero)
await [Link]()
await [Link](hero)
return hero
SQLModel provides a powerful, type-safe way to work with SQL databases while maintaining the
flexibility and performance of SQLAlchemy with the developer experience of Pydantic.
Page 6 of 6