From ce8eac9aba206d79af51ab6ed2761a468aaa8b32 Mon Sep 17 00:00:00 2001 From: Anas Khan <83116240+anxkhn@users.noreply.github.com> Date: Sun, 5 Jul 2026 15:37:22 +0530 Subject: [PATCH] fix: add SET DEFAULT and NO ACTION to OnDeleteType The OnDeleteType literal that types Field(ondelete=...) only listed CASCADE, SET NULL and RESTRICT, so type checkers rejected the other two standard SQL referential actions, SET DEFAULT and NO ACTION, even though both are valid at runtime and emit correct ON DELETE DDL via SQLAlchemy. Add the two missing actions to the literal and cover them with a parametrized regression test asserting the generated foreign key and DDL. --- sqlmodel/main.py | 2 +- tests/test_main.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index c551afea36..3ff3a97232 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -87,7 +87,7 @@ | Mapping[int, Union["IncEx", bool]] | Mapping[str, Union["IncEx", bool]] ) -OnDeleteType = Literal["CASCADE", "SET NULL", "RESTRICT"] +OnDeleteType = Literal["CASCADE", "SET NULL", "SET DEFAULT", "RESTRICT", "NO ACTION"] def __dataclass_transform__( diff --git a/tests/test_main.py b/tests/test_main.py index fa40b71853..0ca1fe9e5a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -3,6 +3,7 @@ import pytest from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import RelationshipProperty +from sqlalchemy.schema import CreateTable from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select @@ -216,3 +217,26 @@ class Hero(SQLModel, table=True): assert len(foreign_keys) == 1 assert foreign_keys[0].ondelete == "CASCADE" assert team_id_column.nullable is False + + +@pytest.mark.parametrize("ondelete", ["SET DEFAULT", "NO ACTION"]) +def test_foreign_key_ondelete_referential_actions(clear_sqlmodel, ondelete): + class Team(SQLModel, table=True): + id: int | None = Field(default=None, primary_key=True) + + class Hero(SQLModel, table=True): + id: int | None = Field(default=None, primary_key=True) + team_id: int | None = Field( + default=None, foreign_key="team.id", ondelete=ondelete + ) + + engine = create_engine("sqlite://") + SQLModel.metadata.create_all(engine) + + hero_table = Hero.__table__ # type: ignore[attr-defined] + foreign_keys = list(hero_table.c.team_id.foreign_keys) + assert len(foreign_keys) == 1 + assert foreign_keys[0].ondelete == ondelete + + ddl = str(CreateTable(hero_table).compile(engine)) + assert f"ON DELETE {ondelete}" in ddl