Skip to content

Clear removed model options in AlterModelOptions - #2280

Merged
waketzheng merged 3 commits into
tortoise:developfrom
edu2004eu:fix/altermodeloptions-remove-keys
Sep 14, 2026
Merged

waketzheng merged 3 commits into
tortoise:developfrom
edu2004eu:fix/altermodeloptions-remove-keys

Conversation

@edu2004eu

Copy link
Copy Markdown
Contributor

Description

AlterModelOptions.state_forward applied its options with model_state.options.update(...), which can only add or change keys. When an option is removed from a model the generator emits an AlterModelOptions whose options simply don't contain it, so the old value stayed in the state and the same operation was emitted again on the next run.

This clears the keys that belong to this operation and aren't in the new options. The five keys carried by other operations (table, app, indexes, unique_together, constraints) are left alone — that list already existed as a literal in _model_options_for_compare, so I moved it to AlterModelOptions.UNMANAGED_OPTION_KEYS and had the diff use it. The bug was the two sides disagreeing about which keys this operation owns, so it seemed worth having one definition.

Motivation and Context

Fixes #2279.

Deleting a model's docstring clears table_description, and from then on makemigrations writes the same migration on every run and never gets back to No changes detected. In a project with a few such models, every later migration carries a block of no-op operations unrelated to the change being made.

In practice table_description is the only key this affects today, since pk_attr is always present.

Not covered here: database_forward returns None and table comments are only written by CreateModel, so on PostgreSQL a changed or deleted docstring still never reaches COMMENT ON TABLE. Same root cause, but it needs SQL emission per backend, so I left it out of this PR.

How Has This Been Tested?

Three tests, in the files already covering these units:

  • test_alter_options_removes_dropped_key — a removed key is gone from the state after the operation applies.
  • test_alter_options_keeps_unmanaged_keysunique_together and table survive, guarding against the clearing being too broad.
  • test_removing_table_description_settles_after_one_migration — generates the operation, applies it, and asserts the next diff is empty. This is the reported symptom.

The first and third fail on develop and pass with the change.

Also reproduced end to end before and after: a one-model SQLite project, docstring removed, makemigrations + migrate three times. Before, three identical migrations; after, one, then No changes detected.

make check passes. pytest tests/migrations/ is 302 passed, 6 skipped; the full SQLite suite is 1917 passed, 148 skipped, 2 xfailed. One unrelated failure locally, tests/fields/test_time.py::test_zoneinfo, is a missing tzdata on my machine and fails the same way without this change.

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.

state_forward merged the new options into the state, so an option dropped
from the model (such as a table_description from a deleted docstring) stayed
behind and makemigrations re-emitted the same operation on every run.
@codspeed-hq

codspeed-hq Bot commented Sep 12, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing edu2004eu:fix/altermodeloptions-remove-keys (293d430) with develop (e5bddf2)

Open in CodSpeed

Comment thread tortoise/migrations/operations.py Outdated
@waketzheng
waketzheng merged commit d6ce10f into tortoise:develop Sep 14, 2026
20 of 25 checks passed
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.

makemigrations keeps regenerating the same migration after a model docstring is removed

3 participants