Skip to content

Fix db_default on FK/O2O dropped during _init_relations#2200

Open
mixartemev wants to merge 1 commit into
tortoise:developfrom
mixartemev:fix/fk-db-default
Open

Fix db_default on FK/O2O dropped during _init_relations#2200
mixartemev wants to merge 1 commit into
tortoise:developfrom
mixartemev:fix/fk-db-default

Conversation

@mixartemev
Copy link
Copy Markdown

Description

_init_relations builds the implicit <fk>_id key field by copying the related model's PK field and then patching a small set of attributes from the FK object:

for attr in ("index", "default", "null", "generated", "description"):
    setattr(key_fk_object, attr, getattr(fk_object, attr))

db_default is missing from this list. The schema editor then iterates fields_db_projection (which holds the key field, not the FK relation field) and inspects key_field.has_db_default(). It returns False, so CREATE TABLE for the owning model is emitted without a DEFAULT clause on the FK column — even when db_default=... is set on the ForeignKeyField / OneToOneField and faithfully recorded in the generated migration.

This fix adds "db_default" to the attribute-copy tuple. Same path covers OneToOneField since both go through init_fk_o2o_field.

Motivation and Context

Fixes #2199

PR #2129 fixed the same omission for non-relation fields (the schema editor now emits DEFAULT for plain columns). This is the FK twin of that bug, living one layer up in Apps._init_relations — the schema editor never gets a chance to see the default because it isn't on the key field.

How Has This Been Tested?

Added test_create_model_includes_db_default_on_fk in tests/migrations/test_schema_editor_sql.py:

  1. Declares a target model Dc and a model App with dc = ForeignKeyField("models.Dc", db_default=2).
  2. Runs init_apps(Dc, App) (which exercises StateApps._init_relations — the fixed path).
  3. Calls create_model(App) via the schema editor.
  4. Asserts the SQL contains "dc_id" and DEFAULT 2.

The test fails on develop HEAD without the fix (verified locally), and passes with it. All 298 existing migration tests continue to pass.

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added the changelog accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

When db_default is set on a ForeignKeyField/OneToOneField, the value
never reaches the generated DDL: `_init_relations` builds the implicit
`<fk>_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 tortoise#2129 fixed the same
omission for non-relation fields.

Fixes tortoise#2199
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FK/O2O db_default is dropped during _init_relations (CREATE TABLE omits DEFAULT on FK columns)

1 participant