From bc4045abd99936d70bd115ea37744dd3521afce0 Mon Sep 17 00:00:00 2001 From: xync Date: Thu, 21 May 2026 01:02:31 +0300 Subject: [PATCH 1/3] Fix db_default on ForeignKey/OneToOne dropped during _init_relations When db_default is set on a ForeignKeyField/OneToOneField, the value never reaches the generated DDL: `_init_relations` builds the implicit `_id` key field by copying the related model's PK and patching a small set of attributes from the FK object, but `db_default` is not in that list. The schema editor then iterates fields_db_projection (which contains the key field) and finds has_db_default() == False, so the CREATE TABLE for the owning model has no DEFAULT clause on the FK column. Add `db_default` to the attribute-copy tuple so it propagates from the FK to the underlying column, mirroring how PR #2129 fixed the same omission for non-relation fields. Fixes #2199 --- CHANGELOG.rst | 1 + tests/migrations/test_schema_editor_sql.py | 33 ++++++++++++++++++++++ tortoise/apps.py | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b111c9525..a6fa2cfae 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,6 +21,7 @@ Added Fixed ^^^^^ - ``MigrationRecorder`` now uses parameterized queries; fixes MariaDB/MySQL rejecting ISO-8601 ``applied_at`` values. (#2132) +- ``db_default`` on ``ForeignKeyField``/``OneToOneField`` now propagates to the underlying ``_id`` column, so ``CREATE TABLE`` emits the ``DEFAULT`` clause for FK columns. (#2199) 1.1.7 ----- diff --git a/tests/migrations/test_schema_editor_sql.py b/tests/migrations/test_schema_editor_sql.py index ee9ca8860..30578f5f8 100644 --- a/tests/migrations/test_schema_editor_sql.py +++ b/tests/migrations/test_schema_editor_sql.py @@ -249,3 +249,36 @@ class Meta: sql = client.executed[0] assert 'CREATE TABLE "widget"' in sql assert "DEFAULT 'active'" in sql + + +@pytest.mark.asyncio +async def test_create_model_includes_db_default_on_fk() -> None: + """CreateModel should include DEFAULT clause for FK columns with db_default.""" + + class Dc(Model): + id = fields.IntField(pk=True) + + class Meta: + table = "dc" + app = "models" + + class App(Model): + id = fields.IntField(pk=True) + dc = fields.ForeignKeyField("models.Dc", db_default=2) + + class Meta: + table = "app" + app = "models" + + init_apps(Dc, App) + + client = FakeClient("sql") + editor = TestSchemaEditor(client) + + await editor.create_model(App) + + assert len(client.executed) == 1 + sql = client.executed[0] + assert 'CREATE TABLE "app"' in sql + assert '"dc_id"' in sql + assert "DEFAULT 2" in sql diff --git a/tortoise/apps.py b/tortoise/apps.py index f2be4800f..637ba142b 100644 --- a/tortoise/apps.py +++ b/tortoise/apps.py @@ -192,7 +192,7 @@ def init_fk_o2o_field(model: type[Model], field: str, is_o2o: bool = False) -> N key_field = f"{field}_id" key_fk_object.reference = fk_object key_fk_object.source_field = fk_object.source_field or key_field - for attr in ("index", "default", "null", "generated", "description"): + for attr in ("index", "default", "null", "generated", "description", "db_default"): setattr(key_fk_object, attr, getattr(fk_object, attr)) if is_o2o: key_fk_object.pk = fk_object.pk From fc0adba743a095db523cb537104636f908406dfd Mon Sep 17 00:00:00 2001 From: Mike Artemiev Date: Tue, 26 May 2026 11:43:09 +0300 Subject: [PATCH 2/3] Add type annotation to FK field in test for mypy --- tests/migrations/test_schema_editor_sql.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/migrations/test_schema_editor_sql.py b/tests/migrations/test_schema_editor_sql.py index 30578f5f8..4aaf1147f 100644 --- a/tests/migrations/test_schema_editor_sql.py +++ b/tests/migrations/test_schema_editor_sql.py @@ -264,7 +264,7 @@ class Meta: class App(Model): id = fields.IntField(pk=True) - dc = fields.ForeignKeyField("models.Dc", db_default=2) + dc: fields.ForeignKeyRelation[Dc] = fields.ForeignKeyField("models.Dc", db_default=2) class Meta: table = "app" From f7bbc6a07dcc0f3220566919226086cd8a3dbf3e Mon Sep 17 00:00:00 2001 From: Mike Artemiev Date: Wed, 27 May 2026 18:48:12 +0300 Subject: [PATCH 3/3] Update primary key field declaration syntax pk-> primary_key --- tests/migrations/test_schema_editor_sql.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/migrations/test_schema_editor_sql.py b/tests/migrations/test_schema_editor_sql.py index 4aaf1147f..67a9dac31 100644 --- a/tests/migrations/test_schema_editor_sql.py +++ b/tests/migrations/test_schema_editor_sql.py @@ -256,14 +256,14 @@ async def test_create_model_includes_db_default_on_fk() -> None: """CreateModel should include DEFAULT clause for FK columns with db_default.""" class Dc(Model): - id = fields.IntField(pk=True) + id = fields.IntField(primary_key=True) class Meta: table = "dc" app = "models" class App(Model): - id = fields.IntField(pk=True) + id = fields.IntField(primary_key=True) dc: fields.ForeignKeyRelation[Dc] = fields.ForeignKeyField("models.Dc", db_default=2) class Meta: