Add the ability to evolve constraints on a model in Django 2.2+.

Review Request #11121 — Created Aug. 4, 2020 and submitted

Information

Django Evolution
master

Reviewers

Constraints are a feature available in Django 2.2+. They're a way of
listing explicit constraints on a table, for ensuring that a set of
fields are unique (potentially with a conditional query that must also
be met), or for ensuring that a condition passes when inserting data.
These are dependent on the support in the database backend.

A previous change introduced signature storage for constraints, so we
can track the history of constraints and make modifications. This change
completes the support by allowing constraints to be modified through a
ChangeMeta mutation, generating SQL to drop old constraints and add
new ones.

Not all constraint types are available for all databases, or all
versions of databases. Right now, there are effectively three types of
constraints (check constraints, unique constraints, and unique
constraints with a condition). Django already calculates the support for
each of these, and we make use of this when determining which
constraints we can evolve. We also make use of their SQL for evolving
the constraints.

The exception, as always, is SQLite. We still need to perform table
rebuilds to modify the constraints list. This is at least pretty easy.
We simply add any new constraints when building the new table, and leave
out any we want to drop.

This change does introduce our first MySQL support that's dependent on a
newer version of MySQL, or on MariaDB. MySQL does not support check
constraints before MySQL 8.0.16 or MariaDB 10.2.1, and even with those
versions Django won't generate SQL prior to Django 3.0. Since we're just
checking calculated state to determine whether we can use these, there
isn't really any impact to our evolution logic, though we do need to
branch off the SQL tests a bit to expect the right SQL for the MySQL
flavor/version.

Unit tests pass for all versions of Django across all databases.

Summary ID
Add the ability to evolve constraints on a model in Django 2.2+.
Constraints are a feature available in Django 2.2+. They're a way of listing explicit constraints on a table, for ensuring that a set of fields are unique (potentially with a conditional query that must also be met), or for ensuring that a condition passes when inserting data. These are dependent on the support in the database backend. A previous change introduced signature storage for constraints, so we can track the history of constraints and make modifications. This change completes the support by allowing constraints to be modified through a `ChangeMeta` mutation, generating SQL to drop old constraints and add new ones. Not all constraint types are available for all databases, or all versions of databases. Right now, there are effectively three types of constraints (check constraints, unique constraints, and unique constraints with a condition). Django already calculates the support for each of these, and we make use of this when determining which constraints we can evolve. We also make use of their SQL for evolving the constraints. The exception, as always, is SQLite. We still need to perform table rebuilds to modify the constraints list. This is at least pretty easy. We simply add any new constraints when building the new table, and leave out any we want to drop. This change does introduce our first MySQL support that's dependent on a newer version of MySQL, or on MariaDB. MySQL does not support check constraints before MySQL 8.0.16 or MariaDB 10.2.1, and even with those versions Django won't generate SQL prior to Django 3.0. Since we're just checking calculated state to determine whether we can use these, there isn't really any impact to our evolution logic, though we do need to branch off the SQL tests a bit to expect the right SQL for the MySQL flavor/version.
0a630076655431a8668c59a26522891b4121281f
Description From Last Updated

F841 local variable 'table_name' is assigned to but never used

reviewbotreviewbot

F841 local variable 'deleted_constraints' is assigned to but never used

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

flake8

chipx86
david
  1. Ship It!
  2. 
      
chipx86
Review request changed
Status:
Completed
Change Summary:
Pushed to master (75f72c5)