Fix ChangeField failure with index+column type changes on MySQL.

Review Request #14922 — Created March 17, 2026 and updated

Information

Django Evolution
master

Reviewers

When a ChangeField mutation changes both the field type and
unique/db_index attributes, MySQL's MODIFY COLUMN runs before the
index is dropped. MySQL rejects this for TEXT or BLOB columns with
the error "BLOB/TEXT column used in key specification without a key
length".

This happened because ChangeField.mutate() returns early after
change_column_type() when change_column_type_sets_attrs is True
(MySQL), skipping the change_column_attrs() call that handles index
drops.

change_column_type() now processes db_index/unique changes from
new_attrs when change_column_type_sets_attrs is True, emitting
index drops as pre-SQL (before the MODIFY) and index adds as post-SQL
(after). The SQLite3 backend also calls the new helper to keep in-memory
database state in sync.

  • Ran unit tests without the fix and verified that the new tests failed with
    the same issue I saw in the wild.
  • Ran unit tests with the fix and verified that it was now fixed.
  • Ran dbtests for mysql, sqlite, and postgresql.
Summary ID
Fix ChangeField failure with index+column type changes on MySQL.
When a `ChangeField` mutation changes both the field type and `unique`/`db_index` attributes, MySQL's `MODIFY COLUMN` runs before the index is dropped. MySQL rejects this for `TEXT` or `BLOB` columns with the error "BLOB/TEXT column used in key specification without a key length". This happened because `ChangeField.mutate()` returns early after `change_column_type()` when `change_column_type_sets_attrs` is `True` (MySQL), skipping the `change_column_attrs()` call that handles index drops. `change_column_type()` now processes `db_index`/`unique` changes from `new_attrs` when `change_column_type_sets_attrs` is `True`, emitting index drops as pre-SQL (before the `MODIFY`) and index adds as post-SQL (after). The SQLite3 backend also calls the new helper to keep in-memory database state in sync. Testing Done: - Ran unit tests without the fix and verified that the new tests failed with the same issue I saw in the wild. - Ran unit tests with the fix and verified that it was now fixed. - Ran dbtests for mysql, sqlite, and postgresql.
qnonyqrrwwqqowzwqpqlwpvvslzxpvum
Description From Last Updated

continuation line over-indented for visual indent Column: 48 Error code: E127

reviewbotreviewbot
Checks run (1 failed, 1 succeeded)
flake8 failed.
JSHint passed.

flake8

david
Review request changed
Commits:
Summary ID
Fix ChangeField failure with index+column type changes on MySQL.
When a `ChangeField` mutation changes both the field type and `unique`/`db_index` attributes, MySQL's `MODIFY COLUMN` runs before the index is dropped. MySQL rejects this for `TEXT` or `BLOB` columns with the error "BLOB/TEXT column used in key specification without a key length". This happened because `ChangeField.mutate()` returns early after `change_column_type()` when `change_column_type_sets_attrs` is `True` (MySQL), skipping the `change_column_attrs()` call that handles index drops. `change_column_type()` now processes `db_index`/`unique` changes from `new_attrs` when `change_column_type_sets_attrs` is `True`, emitting index drops as pre-SQL (before the `MODIFY`) and index adds as post-SQL (after). The SQLite3 backend also calls the new helper to keep in-memory database state in sync. Testing Done: - Ran unit tests without the fix and verified that the new tests failed with the same issue I saw in the wild. - Ran unit tests with the fix and verified that it was now fixed. - Ran dbtests for mysql, sqlite, and postgresql.
qnonyqrrwwqqowzwqpqlwpvvslzxpvum
Fix ChangeField failure with index+column type changes on MySQL.
When a `ChangeField` mutation changes both the field type and `unique`/`db_index` attributes, MySQL's `MODIFY COLUMN` runs before the index is dropped. MySQL rejects this for `TEXT` or `BLOB` columns with the error "BLOB/TEXT column used in key specification without a key length". This happened because `ChangeField.mutate()` returns early after `change_column_type()` when `change_column_type_sets_attrs` is `True` (MySQL), skipping the `change_column_attrs()` call that handles index drops. `change_column_type()` now processes `db_index`/`unique` changes from `new_attrs` when `change_column_type_sets_attrs` is `True`, emitting index drops as pre-SQL (before the `MODIFY`) and index adds as post-SQL (after). The SQLite3 backend also calls the new helper to keep in-memory database state in sync. Testing Done: - Ran unit tests without the fix and verified that the new tests failed with the same issue I saw in the wild. - Ran unit tests with the fix and verified that it was now fixed. - Ran dbtests for mysql, sqlite, and postgresql.
qnonyqrrwwqqowzwqpqlwpvvslzxpvum

Checks run (2 succeeded)

flake8 passed.
JSHint passed.