Add common database backend support for changing field types.

Review Request #12232 — Created April 8, 2022 and submitted — Latest diff uploaded


Django Evolution


This introduces new methods on BaseEvolutionOperations for changing a
field type:

  • change_column_type(): Orchestrates changing the type of a field,
    dropping/re-adding any constraints and updating the types of any
    fields pointing to the changed field.

  • get_change_column_type_sql(): Returns backend-specific SQL for
    changing the type of any given field.

Along with a new capability attribute, change_column_type_sets_attrs,
which states whether get_change_column_type_sql() will also handle
setting all the attributes for the field definition. If False,
attributes need to be set in a separate change_column_attrs() call.

The basic strategy for changing a field type is:

  1. Any constraints pointing to the changed field must be dropped, in
    order to avoid issues with incompatible data types between the
    referring fields and the changed field.

  2. The field type can then safely be changed. Depending on the database
    backend, the command for this may include the entire field definition
    (NOT NULL, VARCHAR(...), etc.), or it may not (requiring that
    these changes are made separately, if needed). This part is not
    currently implemented by any backends.

  3. Any fields referring to the changed field need to be updated to match
    the field type.

  4. Constraints dropped in step 1 can then be restored.

BaseEvolutionOperations takes care of all of this by default, leaving
most backends responsible only for the capability attribute and the
implementation of get_change_column_type_sql(). Subclasses are free
to override the entire process, if needed.

Upcoming changes will implement the per-database support, the
orchestration in ChangeField and related objects, and the test suite.

Tested along with the other upcoming changes for this feature. All unit
tests pass on all supported databases and versions of Django.