0% found this document useful (0 votes)
4 views

SQL (Relational) Databases - FastAPI

FastAPI allows the use of any database, including SQL and NoSQL options, but provides an example using SQLModel, which is built on SQLAlchemy and Pydantic. The tutorial demonstrates how to set up a simple FastAPI application with SQLite, including creating a model for 'Hero', and implementing CRUD operations. For production applications, it suggests using a database server like PostgreSQL and provides resources for further learning.

Uploaded by

garrettfmineau
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

SQL (Relational) Databases - FastAPI

FastAPI allows the use of any database, including SQL and NoSQL options, but provides an example using SQLModel, which is built on SQLAlchemy and Pydantic. The tutorial demonstrates how to set up a simple FastAPI application with SQLite, including creating a model for 'Hero', and implementing CRUD operations. For production applications, it suggests using a database server like PostgreSQL and provides resources for further learning.

Uploaded by

garrettfmineau
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 228

4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

FastAPI Learn Tutorial - User Guide

SQL (Relational) Databases

FastAPI doesn't require you to use a SQL (relational) database. But you can use any database that
you want.

Here we'll see an example using SQLModel [ ↪].


SQLModel is built on top of SQLAlchemy [ ↪] and Pydantic. It was made by the same author of
FastAPI to be the perfect match for FastAPI applications that need to use SQL databases.

Tip

You could use any other SQL or NoSQL database library you want (in some cases called "ORMs"),
FastAPI doesn't force you to use anything. 😎

As SQLModel is based on SQLAlchemy, you can easily use any database supported by
SQLAlchemy (which makes them also supported by SQLModel), like:

PostgreSQL

MySQL

SQLite

Oracle

Microsoft SQL Server, etc.

In this example, we'll use SQLite, because it uses a single file and Python has integrated support.
So, you can copy this example and run it as is.

Later, for your production application, you might want to use a database server like PostgreSQL.

Tip

There is an official project generator with FastAPI and PostgreSQL including a frontend and more
tools: https://github.com/fastapi/full-stack-fastapi-template [ ↪]

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 1/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

This is a very simple and short tutorial, if you want to learn about databases in general, about SQL,
or more advanced features, go to the SQLModel docs [ ↪].

Install SQLModel
First, make sure you create your virtual environment ↪, activate it, and then install sqlmodel :

bash

$ pip install sqlmodel


████████████████████████████████████████ 100%

restart ↻

Create the App with a Single Model


We'll create the simplest first version of the app with a single SQLModel model first.

Later we'll improve it increasing security and versatility with multiple models below. 🤓
Create Models

Import SQLModel and create a database model:

Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 2/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 3/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 4/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 5/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 6/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 7/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 8/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 9/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 10/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 11/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 12/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

The Hero class is very similar to a Pydantic model (in fact, underneath, it actually is a Pydantic
model).

There are a few differences:

table=True tells SQLModel that this is a table model, it should represent a table in the SQL
database, it's not just a data model (as would be any other regular Pydantic class).

Field(primary_key=True) tells SQLModel that the id is the primary key in the SQL
database (you can learn more about SQL primary keys in the SQLModel docs).

By having the type as int | None , SQLModel will know that this column should be an
INTEGER in the SQL database and that it should be NULLABLE .

Field(index=True) tells SQLModel that it should create a SQL index for this column, that
would allow faster lookups in the database when reading data filtered by this column.

SQLModel will know that something declared as str will be a SQL column of type TEXT (or
VARCHAR , depending on the database).

Create an Engine

A SQLModel engine (underneath it's actually a SQLAlchemy engine ) is what holds the
connections to the database.

You would have one single engine object for all your code to connect to the same database.

Python 3.10+

# Code above omitted 👆


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 13/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 14/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 15/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 16/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 17/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 18/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 19/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 20/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 21/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 22/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Using check_same_thread=False allows FastAPI to use the same SQLite database in different
threads. This is necessary as one single request could use more than one thread (for example in
dependencies).

Don't worry, with the way the code is structured, we'll make sure we use a single SQLModel session
per request later, this is actually what the check_same_thread is trying to achieve.

Create the Tables

We then add a function that uses SQLModel.metadata.create_all(engine) to create the tables


for all the table models.

Python 3.10+

# Code above omitted 👆


def create_db_and_tables():
SQLModel.metadata.create_all(engine)

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 23/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 24/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 25/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 26/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 27/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 28/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 29/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 30/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 31/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 32/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Create a Session Dependency

A Session is what stores the objects in memory and keeps track of any changes needed in the
data, then it uses the engine to communicate with the database.

We will create a FastAPI dependency with yield that will provide a new Session for each
request. This is what ensures that we use a single session per request. 🤓
Then we create an Annotated dependency SessionDep to simplify the rest of the code that will
use this dependency.

Python 3.10+

# Code above omitted 👆


def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 33/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 34/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 35/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 36/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 37/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 38/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 39/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 40/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 41/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 42/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Create Database Tables on Startup

We will create the database tables when the application starts.

Python 3.10+

# Code above omitted 👆


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 43/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 44/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 45/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 46/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 47/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 48/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 49/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 50/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 51/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 52/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Here we create the tables on an application startup event.

For production you would probably use a migration script that runs before you start your app. 🤓
Tip

SQLModel will have migration utilities wrapping Alembic, but for now, you can use Alembic [ ↪]
directly.

Create a Hero

Because each SQLModel model is also a Pydantic model, you can use it in the same type
annotations that you could use Pydantic models.

For example, if you declare a parameter of type Hero , it will be read from the JSON body.

The same way, you can declare it as the function's return type, and then the shape of the data will
show up in the automatic API docs UI.

Python 3.10+

# Code above omitted 👆


@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 53/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 54/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 55/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 56/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 57/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 58/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 59/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 60/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 61/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 62/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Here we use the SessionDep dependency (a Session ) to add the new Hero to the Session
instance, commit the changes to the database, refresh the data in the hero , and then return it.

Read Heroes

We can read Hero s from the database using a select() . We can include a limit and offset to
paginate the results.

Python 3.10+

# Code above omitted 👆


@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 63/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 64/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 65/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 66/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 67/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 68/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 69/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 70/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 71/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 72/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Read One Hero

We can read a single Hero .

Python 3.10+

# Code above omitted 👆


@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 73/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 74/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 75/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 76/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 77/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 78/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 79/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 80/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 81/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 82/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Delete a Hero

We can also delete a Hero .

Python 3.10+

# Code above omitted 👆


@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 83/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 84/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 85/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 86/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 87/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

SessionDep = Annotated[Session, Depends(get_session)]

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 88/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

class Hero(SQLModel, table=True):


id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 89/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)
secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 90/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> list[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
name: str = Field(index=True)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 91/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

age: Union[int, None] = Field(default=None, index=True)


secret_name: str

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
session.add(hero)
session.commit()
session.refresh(hero)
return hero

@app.get("/heroes/")
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
) -> List[Hero]:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 92/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Run the App

You can run the app:

bash

$ fastapi dev main.py

INFO: Uvicorn running on http://127.0.0.1:8000


(Press CTRL+C to quit)
restart ↻

Then go to the /docs UI, you will see that FastAPI is using these models to document the API, and
it will use them to serialize and validate the data too.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 93/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Update the App with Multiple Models


Now let's refactor this app a bit to increase security and versatility.

If you check the previous app, in the UI you can see that, up to now, it lets the client decide the id
of the Hero to create. 😱

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 94/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

We shouldn't let that happen, they could overwrite an id we already have assigned in the DB.
Deciding the id should be done by the backend or the database, not by the client.

Additionally, we create a secret_name for the hero, but so far, we are returning it everywhere, that's
not very secret... 😅
We'll fix these things by adding a few extra models. Here's where SQLModel will shine. ✨
Create Multiple Models

In SQLModel, any model class that has table=True is a table model.

And any model class that doesn't have table=True is a data model, these ones are actually just
Pydantic models (with a couple of small extra features). 🤓
With SQLModel, we can use inheritance to avoid duplicating all the fields in all the cases.

HeroBase - the base class

Let's start with a HeroBase model that has all the fields that are shared by all the models:

name

age

Python 3.10+

# Code above omitted 👆


class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 95/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 96/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 97/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 98/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 99/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 100/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 101/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 102/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 103/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 104/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 105/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 106/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 107/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Hero - the table model

Then let's create Hero , the actual table model, with the extra fields that are not always in the other
models:

id

secret_name

Because Hero inherits form HeroBase , it also has the fields declared in HeroBase , so all the
fields for Hero are:

id

name

age

secret_name

Python 3.10+

# Code above omitted 👆


class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 108/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 109/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 110/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 111/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 112/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 113/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 114/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 115/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 116/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 117/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 118/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 119/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 120/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

HeroPublic - the public data model

Next, we create a HeroPublic model, this is the one that will be returned to the clients of the API.

It has the same fields as HeroBase , so it won't include secret_name .

Finally, the identity of our heroes is protected! 🥷


It also re-declares id: int . By doing this, we are making a contract with the API clients, so that
they can always expect the id to be there and to be an int (it will never be None ).

Tip

Having the return model ensure that a value is always available and always int (not None ) is very
useful for the API clients, they can write much simpler code having this certainty.

Also, automatically generated clients will have simpler interfaces, so that the developers
communicating with your API can have a much better time working with your API. 😎

All the fields in HeroPublic are the same as in HeroBase , with id declared as int (not None ):

id

name

age

Python 3.10+

# Code above omitted 👆


class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 121/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 122/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 123/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 124/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 125/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 126/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 127/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 128/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 129/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 130/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 131/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 132/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 133/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

HeroCreate - the data model to create a hero

Now we create a HeroCreate model, this is the one that will validate the data from the clients.

It has the same fields as HeroBase , and it also has secret_name .

Now, when the clients create a new hero, they will send the secret_name , it will be stored in the
database, but those secret names won't be returned in the API to the clients.

Tip

This is how you would handle passwords. Receive them, but don't return them in the API.

You would also hash the values of the passwords before storing them, never store them in plain
text.

The fields of HeroCreate are:

name

age

secret_name

Python 3.10+

# Code above omitted 👆


class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 134/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 135/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 136/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 137/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 138/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 139/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 140/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 141/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 142/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 143/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 144/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 145/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 146/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

HeroUpdate - the data model to update a hero

We didn't have a way to update a hero in the previous version of the app, but now with multiple
models, we can do it. 🎉
The HeroUpdate data model is somewhat special, it has all the same fields that would be needed
to create a new hero, but all the fields are optional (they all have a default value). This way, when
you update a hero, you can send just the fields that you want to update.

Because all the fields actually change (the type now includes None and they now have a default
value of None ), we need to re-declare them.

We don't really need to inherit from HeroBase because we are re-declaring all the fields. I'll leave it
inheriting just for consistency, but this is not necessary. It's more a matter of personal taste. 🤷
The fields of HeroUpdate are:

name

age

secret_name

Python 3.10+

# Code above omitted 👆


class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 147/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 148/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 149/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 150/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 151/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 152/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 153/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 154/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 155/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 156/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 157/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 158/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 159/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 160/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Create with HeroCreate and return a HeroPublic

Now that we have multiple models, we can update the parts of the app that use them.

We receive in the request a HeroCreate data model, and from it, we create a Hero table model.

This new table model Hero will have the fields sent by the client, and will also have an id
generated by the database.

Then we return the same table model Hero as is from the function. But as we declare the
response_model with the HeroPublic data model, FastAPI will use HeroPublic to validate and
serialize the data.

Python 3.10+

# Code above omitted 👆


@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 161/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 162/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 163/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 164/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 165/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 166/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 167/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 168/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 169/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 170/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 171/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 172/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 173/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Now we use response_model=HeroPublic instead of the return type annotation -> HeroPublic
because the value that we are returning is actually not a HeroPublic .

If we had declared -> HeroPublic , your editor and linter would complain (rightfully so) that you are
returning a Hero instead of a HeroPublic .

By declaring it in response_model we are telling FastAPI to do its thing, without interfering with the
type annotations and the help from your editor and other tools.

Read Heroes with HeroPublic

We can do the same as before to read Hero s, again, we use response_model=list[HeroPublic]


to ensure that the data is validated and serialized correctly.

Python 3.10+

# Code above omitted 👆


@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 174/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 175/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 176/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 177/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 178/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 179/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 180/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 181/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 182/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 183/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 184/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 185/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 186/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Read One Hero with HeroPublic

We can read a single hero:

Python 3.10+

# Code above omitted 👆


@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 187/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 188/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 189/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 190/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 191/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 192/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 193/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 194/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 195/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 196/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 197/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 198/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 199/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Update a Hero with HeroUpdate

We can update a hero. For this we use an HTTP PATCH operation.

And in the code, we get a dict with all the data sent by the client, only the data sent by the client,
excluding any values that would be there just for being the default values. To do it we use
exclude_unset=True . This is the main trick. 🪄
Then we use hero_db.sqlmodel_update(hero_data) to update the hero_db with the data from
hero_data .

Python 3.10+

# Code above omitted 👆


@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

# Code below omitted 👇

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 200/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 201/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 202/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 203/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 204/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 205/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 206/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 207/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 208/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 209/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 210/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 211/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 212/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Delete a Hero Again

Deleting a hero stays pretty much the same.

We won't satisfy the desire to refactor everything in this one. 😅


Python 3.10+

# Code above omitted 👆


@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 213/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

👀 Full file preview


Python 3.10+

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 214/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 215/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

🤓 Other versions and variants


Python 3.9+

from typing import Annotated, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 216/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 217/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select
from typing_extensions import Annotated

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

SessionDep = Annotated[Session, Depends(get_session)]


app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 218/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

def create_hero(hero: HeroCreate, session: SessionDep):


db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: SessionDep,
offset: int = 0,
limit: Annotated[int, Query(le=100)] = 100,
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.10+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 219/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: int | None = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: int | None = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: str | None = None
age: int | None = None
secret_name: str | None = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 220/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.9+ - non-Annotated

Tip

Prefer to use the Annotated version if possible.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 221/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

from typing import Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 222/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

Python 3.8+ - non-Annotated

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 223/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Tip

Prefer to use the Annotated version if possible.

from typing import List, Union

from fastapi import Depends, FastAPI, HTTPException, Query


from sqlmodel import Field, Session, SQLModel, create_engine, select

class HeroBase(SQLModel):
name: str = Field(index=True)
age: Union[int, None] = Field(default=None, index=True)

class Hero(HeroBase, table=True):


id: Union[int, None] = Field(default=None, primary_key=True)
secret_name: str

class HeroPublic(HeroBase):
id: int

class HeroCreate(HeroBase):
secret_name: str

class HeroUpdate(HeroBase):
name: Union[str, None] = None
age: Union[int, None] = None
secret_name: Union[str, None] = None

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}


engine = create_engine(sqlite_url, connect_args=connect_args)

def create_db_and_tables():
SQLModel.metadata.create_all(engine)

def get_session():
with Session(engine) as session:
yield session

app = FastAPI()

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 224/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

@app.on_event("startup")
def on_startup():
create_db_and_tables()

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
db_hero = Hero.model_validate(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero

@app.get("/heroes/", response_model=List[HeroPublic])
def read_heroes(
session: Session = Depends(get_session),
offset: int = 0,
limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(
hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
):
hero_db = session.get(Hero, hero_id)
if not hero_db:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
hero_db.sqlmodel_update(hero_data)
session.add(hero_db)
session.commit()
session.refresh(hero_db)
return hero_db

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: Session = Depends(get_session)):
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 225/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Run the App Again

You can run the app again:

bash

If you go to the /docs API UI, you will see that it is now updated, and it won't expect to receive the
id from the client when creating a hero, etc.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 226/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

Recap
You can use SQLModel [ ↪] to interact with a SQL database and simplify the code with data models
and table models.

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 227/228
4/18/25, 12:49 PM SQL (Relational) Databases - FastAPI

You can learn a lot more at the SQLModel docs, there's a longer mini
tutorial on using SQLModel with FastAPI [ ↪]. 🚀

Was this page helpful?

https://fastapi.tiangolo.com/tutorial/sql-databases/#heroupdate-the-data-model-to-update-a-hero 228/228

You might also like