Skip to content

Commit 86ab09f

Browse files
estebanx64pre-commit-ci[bot]tiangolo
authored
✨ Add support for cascade delete relationships: cascade_delete, ondelete, and passive_deletes (#983)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez <[email protected]>
1 parent 19c7367 commit 86ab09f

37 files changed

+4501
-2
lines changed

docs/tutorial/relationship-attributes/cascade-delete-relationships.md

Lines changed: 1304 additions & 0 deletions
Large diffs are not rendered by default.

docs_src/tutorial/relationship_attributes/cascade_delete_relationships/__init__.py

Whitespace-only changes.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from typing import List, Optional
2+
3+
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select
4+
5+
6+
class Team(SQLModel, table=True):
7+
id: Optional[int] = Field(default=None, primary_key=True)
8+
name: str = Field(index=True)
9+
headquarters: str
10+
11+
heroes: List["Hero"] = Relationship(back_populates="team", cascade_delete=True)
12+
13+
14+
class Hero(SQLModel, table=True):
15+
id: Optional[int] = Field(default=None, primary_key=True)
16+
name: str = Field(index=True)
17+
secret_name: str
18+
age: Optional[int] = Field(default=None, index=True)
19+
20+
team_id: Optional[int] = Field(
21+
default=None, foreign_key="team.id", ondelete="CASCADE"
22+
)
23+
team: Optional[Team] = Relationship(back_populates="heroes")
24+
25+
26+
sqlite_file_name = "database.db"
27+
sqlite_url = f"sqlite:///{sqlite_file_name}"
28+
29+
engine = create_engine(sqlite_url, echo=True)
30+
31+
32+
def create_db_and_tables():
33+
SQLModel.metadata.create_all(engine)
34+
35+
36+
def create_heroes():
37+
with Session(engine) as session:
38+
team_preventers = Team(name="Preventers", headquarters="Sharp Tower")
39+
team_z_force = Team(name="Z-Force", headquarters="Sister Margaret's Bar")
40+
41+
hero_deadpond = Hero(
42+
name="Deadpond", secret_name="Dive Wilson", team=team_z_force
43+
)
44+
hero_rusty_man = Hero(
45+
name="Rusty-Man", secret_name="Tommy Sharp", age=48, team=team_preventers
46+
)
47+
hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
48+
session.add(hero_deadpond)
49+
session.add(hero_rusty_man)
50+
session.add(hero_spider_boy)
51+
session.commit()
52+
53+
session.refresh(hero_deadpond)
54+
session.refresh(hero_rusty_man)
55+
session.refresh(hero_spider_boy)
56+
57+
print("Created hero:", hero_deadpond)
58+
print("Created hero:", hero_rusty_man)
59+
print("Created hero:", hero_spider_boy)
60+
61+
hero_spider_boy.team = team_preventers
62+
session.add(hero_spider_boy)
63+
session.commit()
64+
session.refresh(hero_spider_boy)
65+
print("Updated hero:", hero_spider_boy)
66+
67+
hero_black_lion = Hero(name="Black Lion", secret_name="Trevor Challa", age=35)
68+
hero_sure_e = Hero(name="Princess Sure-E", secret_name="Sure-E")
69+
team_wakaland = Team(
70+
name="Wakaland",
71+
headquarters="Wakaland Capital City",
72+
heroes=[hero_black_lion, hero_sure_e],
73+
)
74+
session.add(team_wakaland)
75+
session.commit()
76+
session.refresh(team_wakaland)
77+
print("Team Wakaland:", team_wakaland)
78+
79+
80+
def delete_team():
81+
with Session(engine) as session:
82+
statement = select(Team).where(Team.name == "Wakaland")
83+
team = session.exec(statement).one()
84+
session.delete(team)
85+
session.commit()
86+
print("Deleted team:", team)
87+
88+
89+
def select_deleted_heroes():
90+
with Session(engine) as session:
91+
statement = select(Hero).where(Hero.name == "Black Lion")
92+
result = session.exec(statement)
93+
hero = result.first()
94+
print("Black Lion not found:", hero)
95+
96+
statement = select(Hero).where(Hero.name == "Princess Sure-E")
97+
result = session.exec(statement)
98+
hero = result.first()
99+
print("Princess Sure-E not found:", hero)
100+
101+
102+
def main():
103+
create_db_and_tables()
104+
create_heroes()
105+
delete_team()
106+
select_deleted_heroes()
107+
108+
109+
if __name__ == "__main__":
110+
main()
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select
2+
3+
4+
class Team(SQLModel, table=True):
5+
id: int | None = Field(default=None, primary_key=True)
6+
name: str = Field(index=True)
7+
headquarters: str
8+
9+
heroes: list["Hero"] = Relationship(back_populates="team", cascade_delete=True)
10+
11+
12+
class Hero(SQLModel, table=True):
13+
id: int | None = Field(default=None, primary_key=True)
14+
name: str = Field(index=True)
15+
secret_name: str
16+
age: int | None = Field(default=None, index=True)
17+
18+
team_id: int | None = Field(default=None, foreign_key="team.id", ondelete="CASCADE")
19+
team: Team | None = Relationship(back_populates="heroes")
20+
21+
22+
sqlite_file_name = "database.db"
23+
sqlite_url = f"sqlite:///{sqlite_file_name}"
24+
25+
engine = create_engine(sqlite_url, echo=True)
26+
27+
28+
def create_db_and_tables():
29+
SQLModel.metadata.create_all(engine)
30+
31+
32+
def create_heroes():
33+
with Session(engine) as session:
34+
team_preventers = Team(name="Preventers", headquarters="Sharp Tower")
35+
team_z_force = Team(name="Z-Force", headquarters="Sister Margaret's Bar")
36+
37+
hero_deadpond = Hero(
38+
name="Deadpond", secret_name="Dive Wilson", team=team_z_force
39+
)
40+
hero_rusty_man = Hero(
41+
name="Rusty-Man", secret_name="Tommy Sharp", age=48, team=team_preventers
42+
)
43+
hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
44+
session.add(hero_deadpond)
45+
session.add(hero_rusty_man)
46+
session.add(hero_spider_boy)
47+
session.commit()
48+
49+
session.refresh(hero_deadpond)
50+
session.refresh(hero_rusty_man)
51+
session.refresh(hero_spider_boy)
52+
53+
print("Created hero:", hero_deadpond)
54+
print("Created hero:", hero_rusty_man)
55+
print("Created hero:", hero_spider_boy)
56+
57+
hero_spider_boy.team = team_preventers
58+
session.add(hero_spider_boy)
59+
session.commit()
60+
session.refresh(hero_spider_boy)
61+
print("Updated hero:", hero_spider_boy)
62+
63+
hero_black_lion = Hero(name="Black Lion", secret_name="Trevor Challa", age=35)
64+
hero_sure_e = Hero(name="Princess Sure-E", secret_name="Sure-E")
65+
team_wakaland = Team(
66+
name="Wakaland",
67+
headquarters="Wakaland Capital City",
68+
heroes=[hero_black_lion, hero_sure_e],
69+
)
70+
session.add(team_wakaland)
71+
session.commit()
72+
session.refresh(team_wakaland)
73+
print("Team Wakaland:", team_wakaland)
74+
75+
76+
def delete_team():
77+
with Session(engine) as session:
78+
statement = select(Team).where(Team.name == "Wakaland")
79+
team = session.exec(statement).one()
80+
session.delete(team)
81+
session.commit()
82+
print("Deleted team:", team)
83+
84+
85+
def select_deleted_heroes():
86+
with Session(engine) as session:
87+
statement = select(Hero).where(Hero.name == "Black Lion")
88+
result = session.exec(statement)
89+
hero = result.first()
90+
print("Black Lion not found:", hero)
91+
92+
statement = select(Hero).where(Hero.name == "Princess Sure-E")
93+
result = session.exec(statement)
94+
hero = result.first()
95+
print("Princess Sure-E not found:", hero)
96+
97+
98+
def main():
99+
create_db_and_tables()
100+
create_heroes()
101+
delete_team()
102+
select_deleted_heroes()
103+
104+
105+
if __name__ == "__main__":
106+
main()
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from typing import Optional
2+
3+
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select
4+
5+
6+
class Team(SQLModel, table=True):
7+
id: Optional[int] = Field(default=None, primary_key=True)
8+
name: str = Field(index=True)
9+
headquarters: str
10+
11+
heroes: list["Hero"] = Relationship(back_populates="team", cascade_delete=True)
12+
13+
14+
class Hero(SQLModel, table=True):
15+
id: Optional[int] = Field(default=None, primary_key=True)
16+
name: str = Field(index=True)
17+
secret_name: str
18+
age: Optional[int] = Field(default=None, index=True)
19+
20+
team_id: Optional[int] = Field(
21+
default=None, foreign_key="team.id", ondelete="CASCADE"
22+
)
23+
team: Optional[Team] = Relationship(back_populates="heroes")
24+
25+
26+
sqlite_file_name = "database.db"
27+
sqlite_url = f"sqlite:///{sqlite_file_name}"
28+
29+
engine = create_engine(sqlite_url, echo=True)
30+
31+
32+
def create_db_and_tables():
33+
SQLModel.metadata.create_all(engine)
34+
35+
36+
def create_heroes():
37+
with Session(engine) as session:
38+
team_preventers = Team(name="Preventers", headquarters="Sharp Tower")
39+
team_z_force = Team(name="Z-Force", headquarters="Sister Margaret's Bar")
40+
41+
hero_deadpond = Hero(
42+
name="Deadpond", secret_name="Dive Wilson", team=team_z_force
43+
)
44+
hero_rusty_man = Hero(
45+
name="Rusty-Man", secret_name="Tommy Sharp", age=48, team=team_preventers
46+
)
47+
hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
48+
session.add(hero_deadpond)
49+
session.add(hero_rusty_man)
50+
session.add(hero_spider_boy)
51+
session.commit()
52+
53+
session.refresh(hero_deadpond)
54+
session.refresh(hero_rusty_man)
55+
session.refresh(hero_spider_boy)
56+
57+
print("Created hero:", hero_deadpond)
58+
print("Created hero:", hero_rusty_man)
59+
print("Created hero:", hero_spider_boy)
60+
61+
hero_spider_boy.team = team_preventers
62+
session.add(hero_spider_boy)
63+
session.commit()
64+
session.refresh(hero_spider_boy)
65+
print("Updated hero:", hero_spider_boy)
66+
67+
hero_black_lion = Hero(name="Black Lion", secret_name="Trevor Challa", age=35)
68+
hero_sure_e = Hero(name="Princess Sure-E", secret_name="Sure-E")
69+
team_wakaland = Team(
70+
name="Wakaland",
71+
headquarters="Wakaland Capital City",
72+
heroes=[hero_black_lion, hero_sure_e],
73+
)
74+
session.add(team_wakaland)
75+
session.commit()
76+
session.refresh(team_wakaland)
77+
print("Team Wakaland:", team_wakaland)
78+
79+
80+
def delete_team():
81+
with Session(engine) as session:
82+
statement = select(Team).where(Team.name == "Wakaland")
83+
team = session.exec(statement).one()
84+
session.delete(team)
85+
session.commit()
86+
print("Deleted team:", team)
87+
88+
89+
def select_deleted_heroes():
90+
with Session(engine) as session:
91+
statement = select(Hero).where(Hero.name == "Black Lion")
92+
result = session.exec(statement)
93+
hero = result.first()
94+
print("Black Lion not found:", hero)
95+
96+
statement = select(Hero).where(Hero.name == "Princess Sure-E")
97+
result = session.exec(statement)
98+
hero = result.first()
99+
print("Princess Sure-E not found:", hero)
100+
101+
102+
def main():
103+
create_db_and_tables()
104+
create_heroes()
105+
delete_team()
106+
select_deleted_heroes()
107+
108+
109+
if __name__ == "__main__":
110+
main()

0 commit comments

Comments
 (0)