fromtypingimportList,OptionalfromfastapiimportDepends,FastAPI,HTTPException,QueryfromsqlmodelimportField,Relationship,Session,SQLModel,create_engine,selectclassTeamBase(SQLModel):name:str=Field(index=True)headquarters:strclassTeam(TeamBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)heroes:List["Hero"]=Relationship(back_populates="team")classTeamCreate(TeamBase):passclassTeamRead(TeamBase):id:intclassTeamUpdate(SQLModel):name:Optional[str]=Noneheadquarters:Optional[str]=NoneclassHeroBase(SQLModel):name:str=Field(index=True)secret_name:strage:Optional[int]=Field(default=None,index=True)team_id:Optional[int]=Field(default=None,foreign_key="team.id")classHero(HeroBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)team:Optional[Team]=Relationship(back_populates="heroes")classHeroRead(HeroBase):id:intclassHeroCreate(HeroBase):passclassHeroUpdate(SQLModel):name:Optional[str]=Nonesecret_name:Optional[str]=Noneage:Optional[int]=Noneteam_id:Optional[int]=Nonesqlite_file_name="database.db"sqlite_url=f"sqlite:///{sqlite_file_name}"connect_args={"check_same_thread":False}engine=create_engine(sqlite_url,echo=True,connect_args=connect_args)defcreate_db_and_tables():SQLModel.metadata.create_all(engine)defget_session():withSession(engine)assession:yieldsessionapp=FastAPI()@app.on_event("startup")defon_startup():create_db_and_tables()@app.post("/heroes/",response_model=HeroRead)defcreate_hero(*,session:Session=Depends(get_session),hero:HeroCreate):db_hero=Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.get("/heroes/",response_model=List[HeroRead])defread_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()returnheroes@app.get("/heroes/{hero_id}",response_model=HeroRead)defread_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")returnhero@app.patch("/heroes/{hero_id}",response_model=HeroRead)defupdate_hero(*,session:Session=Depends(get_session),hero_id:int,hero:HeroUpdate):db_hero=session.get(Hero,hero_id)ifnotdb_hero:raiseHTTPException(status_code=404,detail="Hero not found")hero_data=hero.model_dump(exclude_unset=True)forkey,valueinhero_data.items():setattr(db_hero,key,value)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.delete("/heroes/{hero_id}")defdelete_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")session.delete(hero)session.commit()return{"ok":True}@app.post("/teams/",response_model=TeamRead)defcreate_team(*,session:Session=Depends(get_session),team:TeamCreate):db_team=Team.model_validate(team)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.get("/teams/",response_model=List[TeamRead])defread_teams(*,session:Session=Depends(get_session),offset:int=0,limit:int=Query(default=100,le=100),):teams=session.exec(select(Team).offset(offset).limit(limit)).all()returnteams@app.get("/teams/{team_id}",response_model=TeamRead)defread_team(*,team_id:int,session:Session=Depends(get_session)):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")returnteam@app.patch("/teams/{team_id}",response_model=TeamRead)defupdate_team(*,session:Session=Depends(get_session),team_id:int,team:TeamUpdate,):db_team=session.get(Team,team_id)ifnotdb_team:raiseHTTPException(status_code=404,detail="Team not found")team_data=team.model_dump(exclude_unset=True)forkey,valueinteam_data.items():setattr(db_team,key,value)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.delete("/teams/{team_id}")defdelete_team(*,session:Session=Depends(get_session),team_id:int):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")session.delete(team)session.commit()return{"ok":True}
fromtypingimportList,OptionalfromfastapiimportDepends,FastAPI,HTTPException,QueryfromsqlmodelimportField,Relationship,Session,SQLModel,create_engine,selectclassTeamBase(SQLModel):name:str=Field(index=True)headquarters:strclassTeam(TeamBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)heroes:List["Hero"]=Relationship(back_populates="team")classTeamCreate(TeamBase):passclassTeamRead(TeamBase):id:intclassTeamUpdate(SQLModel):name:Optional[str]=Noneheadquarters:Optional[str]=NoneclassHeroBase(SQLModel):name:str=Field(index=True)secret_name:strage:Optional[int]=Field(default=None,index=True)team_id:Optional[int]=Field(default=None,foreign_key="team.id")classHero(HeroBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)team:Optional[Team]=Relationship(back_populates="heroes")classHeroRead(HeroBase):id:intclassHeroCreate(HeroBase):passclassHeroUpdate(SQLModel):name:Optional[str]=Nonesecret_name:Optional[str]=Noneage:Optional[int]=Noneteam_id:Optional[int]=Nonesqlite_file_name="database.db"sqlite_url=f"sqlite:///{sqlite_file_name}"connect_args={"check_same_thread":False}engine=create_engine(sqlite_url,echo=True,connect_args=connect_args)defcreate_db_and_tables():SQLModel.metadata.create_all(engine)defget_session():withSession(engine)assession:yieldsessionapp=FastAPI()@app.on_event("startup")defon_startup():create_db_and_tables()@app.post("/heroes/",response_model=HeroRead)defcreate_hero(*,session:Session=Depends(get_session),hero:HeroCreate):db_hero=Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.get("/heroes/",response_model=List[HeroRead])defread_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()returnheroes@app.get("/heroes/{hero_id}",response_model=HeroRead)defread_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")returnhero@app.patch("/heroes/{hero_id}",response_model=HeroRead)defupdate_hero(*,session:Session=Depends(get_session),hero_id:int,hero:HeroUpdate):db_hero=session.get(Hero,hero_id)ifnotdb_hero:raiseHTTPException(status_code=404,detail="Hero not found")hero_data=hero.model_dump(exclude_unset=True)forkey,valueinhero_data.items():setattr(db_hero,key,value)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.delete("/heroes/{hero_id}")defdelete_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")session.delete(hero)session.commit()return{"ok":True}@app.post("/teams/",response_model=TeamRead)defcreate_team(*,session:Session=Depends(get_session),team:TeamCreate):db_team=Team.model_validate(team)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.get("/teams/",response_model=List[TeamRead])defread_teams(*,session:Session=Depends(get_session),offset:int=0,limit:int=Query(default=100,le=100),):teams=session.exec(select(Team).offset(offset).limit(limit)).all()returnteams@app.get("/teams/{team_id}",response_model=TeamRead)defread_team(*,team_id:int,session:Session=Depends(get_session)):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")returnteam@app.patch("/teams/{team_id}",response_model=TeamRead)defupdate_team(*,session:Session=Depends(get_session),team_id:int,team:TeamUpdate,):db_team=session.get(Team,team_id)ifnotdb_team:raiseHTTPException(status_code=404,detail="Team not found")team_data=team.model_dump(exclude_unset=True)forkey,valueinteam_data.items():setattr(db_team,key,value)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.delete("/teams/{team_id}")defdelete_team(*,session:Session=Depends(get_session),team_id:int):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")session.delete(team)session.commit()return{"ok":True}
We now have a team_id in the hero models.
Notice that we can declare the team_id in the HeroBase because it can be reused by all the models, in all the cases it's an optional integer.
And even though the HeroBase is not a table model, we can declare team_id in it with the foreign key parameter. It won't do anything in most of the models that inherit from HeroBase, but in the table modelHero it will be used to tell SQLModel that this is a foreign key to that table.
Notice that the relationship attributes, the ones with Relationship(), are only in the table models, as those are the ones that are handled by SQLModel with SQLAlchemy and that can have the automatic fetching of data from the database when we access them.
fromtypingimportList,OptionalfromfastapiimportDepends,FastAPI,HTTPException,QueryfromsqlmodelimportField,Relationship,Session,SQLModel,create_engine,selectclassTeamBase(SQLModel):name:str=Field(index=True)headquarters:strclassTeam(TeamBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)heroes:List["Hero"]=Relationship(back_populates="team")classTeamCreate(TeamBase):passclassTeamRead(TeamBase):id:intclassTeamUpdate(SQLModel):name:Optional[str]=Noneheadquarters:Optional[str]=NoneclassHeroBase(SQLModel):name:str=Field(index=True)secret_name:strage:Optional[int]=Field(default=None,index=True)team_id:Optional[int]=Field(default=None,foreign_key="team.id")classHero(HeroBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)team:Optional[Team]=Relationship(back_populates="heroes")classHeroRead(HeroBase):id:intclassHeroCreate(HeroBase):passclassHeroUpdate(SQLModel):name:Optional[str]=Nonesecret_name:Optional[str]=Noneage:Optional[int]=Noneteam_id:Optional[int]=Nonesqlite_file_name="database.db"sqlite_url=f"sqlite:///{sqlite_file_name}"connect_args={"check_same_thread":False}engine=create_engine(sqlite_url,echo=True,connect_args=connect_args)defcreate_db_and_tables():SQLModel.metadata.create_all(engine)defget_session():withSession(engine)assession:yieldsessionapp=FastAPI()@app.on_event("startup")defon_startup():create_db_and_tables()@app.post("/heroes/",response_model=HeroRead)defcreate_hero(*,session:Session=Depends(get_session),hero:HeroCreate):db_hero=Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.get("/heroes/",response_model=List[HeroRead])defread_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()returnheroes@app.get("/heroes/{hero_id}",response_model=HeroRead)defread_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")returnhero@app.patch("/heroes/{hero_id}",response_model=HeroRead)defupdate_hero(*,session:Session=Depends(get_session),hero_id:int,hero:HeroUpdate):db_hero=session.get(Hero,hero_id)ifnotdb_hero:raiseHTTPException(status_code=404,detail="Hero not found")hero_data=hero.model_dump(exclude_unset=True)forkey,valueinhero_data.items():setattr(db_hero,key,value)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.delete("/heroes/{hero_id}")defdelete_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")session.delete(hero)session.commit()return{"ok":True}@app.post("/teams/",response_model=TeamRead)defcreate_team(*,session:Session=Depends(get_session),team:TeamCreate):db_team=Team.model_validate(team)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.get("/teams/",response_model=List[TeamRead])defread_teams(*,session:Session=Depends(get_session),offset:int=0,limit:int=Query(default=100,le=100),):teams=session.exec(select(Team).offset(offset).limit(limit)).all()returnteams@app.get("/teams/{team_id}",response_model=TeamRead)defread_team(*,team_id:int,session:Session=Depends(get_session)):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")returnteam@app.patch("/teams/{team_id}",response_model=TeamRead)defupdate_team(*,session:Session=Depends(get_session),team_id:int,team:TeamUpdate,):db_team=session.get(Team,team_id)ifnotdb_team:raiseHTTPException(status_code=404,detail="Team not found")team_data=team.model_dump(exclude_unset=True)forkey,valueinteam_data.items():setattr(db_team,key,value)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.delete("/teams/{team_id}")defdelete_team(*,session:Session=Depends(get_session),team_id:int):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")session.delete(team)session.commit()return{"ok":True}
These are equivalent and very similar to the path operations for the heroes we had before, so we don't have to go over the details for each one, let's check the code.
# Code above omitted 👆@app.post("/teams/",response_model=TeamRead)defcreate_team(*,session:Session=Depends(get_session),team:TeamCreate):db_team=Team.model_validate(team)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.get("/teams/",response_model=List[TeamRead])defread_teams(*,session:Session=Depends(get_session),offset:int=0,limit:int=Query(default=100,le=100),):teams=session.exec(select(Team).offset(offset).limit(limit)).all()returnteams@app.get("/teams/{team_id}",response_model=TeamRead)defread_team(*,team_id:int,session:Session=Depends(get_session)):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")returnteam@app.patch("/teams/{team_id}",response_model=TeamRead)defupdate_team(*,session:Session=Depends(get_session),team_id:int,team:TeamUpdate,):db_team=session.get(Team,team_id)ifnotdb_team:raiseHTTPException(status_code=404,detail="Team not found")team_data=team.model_dump(exclude_unset=True)forkey,valueinteam_data.items():setattr(db_team,key,value)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.delete("/teams/{team_id}")defdelete_team(*,session:Session=Depends(get_session),team_id:int):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")session.delete(team)session.commit()return{"ok":True}# Code below omitted 👇
👀 Full file preview
fromtypingimportList,OptionalfromfastapiimportDepends,FastAPI,HTTPException,QueryfromsqlmodelimportField,Relationship,Session,SQLModel,create_engine,selectclassTeamBase(SQLModel):name:str=Field(index=True)headquarters:strclassTeam(TeamBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)heroes:List["Hero"]=Relationship(back_populates="team")classTeamCreate(TeamBase):passclassTeamRead(TeamBase):id:intclassTeamUpdate(SQLModel):name:Optional[str]=Noneheadquarters:Optional[str]=NoneclassHeroBase(SQLModel):name:str=Field(index=True)secret_name:strage:Optional[int]=Field(default=None,index=True)team_id:Optional[int]=Field(default=None,foreign_key="team.id")classHero(HeroBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)team:Optional[Team]=Relationship(back_populates="heroes")classHeroRead(HeroBase):id:intclassHeroCreate(HeroBase):passclassHeroUpdate(SQLModel):name:Optional[str]=Nonesecret_name:Optional[str]=Noneage:Optional[int]=Noneteam_id:Optional[int]=Nonesqlite_file_name="database.db"sqlite_url=f"sqlite:///{sqlite_file_name}"connect_args={"check_same_thread":False}engine=create_engine(sqlite_url,echo=True,connect_args=connect_args)defcreate_db_and_tables():SQLModel.metadata.create_all(engine)defget_session():withSession(engine)assession:yieldsessionapp=FastAPI()@app.on_event("startup")defon_startup():create_db_and_tables()@app.post("/heroes/",response_model=HeroRead)defcreate_hero(*,session:Session=Depends(get_session),hero:HeroCreate):db_hero=Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.get("/heroes/",response_model=List[HeroRead])defread_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()returnheroes@app.get("/heroes/{hero_id}",response_model=HeroRead)defread_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")returnhero@app.patch("/heroes/{hero_id}",response_model=HeroRead)defupdate_hero(*,session:Session=Depends(get_session),hero_id:int,hero:HeroUpdate):db_hero=session.get(Hero,hero_id)ifnotdb_hero:raiseHTTPException(status_code=404,detail="Hero not found")hero_data=hero.model_dump(exclude_unset=True)forkey,valueinhero_data.items():setattr(db_hero,key,value)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.delete("/heroes/{hero_id}")defdelete_hero(*,session:Session=Depends(get_session),hero_id:int):hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")session.delete(hero)session.commit()return{"ok":True}@app.post("/teams/",response_model=TeamRead)defcreate_team(*,session:Session=Depends(get_session),team:TeamCreate):db_team=Team.model_validate(team)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.get("/teams/",response_model=List[TeamRead])defread_teams(*,session:Session=Depends(get_session),offset:int=0,limit:int=Query(default=100,le=100),):teams=session.exec(select(Team).offset(offset).limit(limit)).all()returnteams@app.get("/teams/{team_id}",response_model=TeamRead)defread_team(*,team_id:int,session:Session=Depends(get_session)):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")returnteam@app.patch("/teams/{team_id}",response_model=TeamRead)defupdate_team(*,session:Session=Depends(get_session),team_id:int,team:TeamUpdate,):db_team=session.get(Team,team_id)ifnotdb_team:raiseHTTPException(status_code=404,detail="Team not found")team_data=team.model_dump(exclude_unset=True)forkey,valueinteam_data.items():setattr(db_team,key,value)session.add(db_team)session.commit()session.refresh(db_team)returndb_team@app.delete("/teams/{team_id}")defdelete_team(*,session:Session=Depends(get_session),team_id:int):team=session.get(Team,team_id)ifnotteam:raiseHTTPException(status_code=404,detail="Team not found")session.delete(team)session.commit()return{"ok":True}