Add the ability to evolve constraints on a model in Django 2.2+.
Review Request #11121 — Created Aug. 4, 2020 and submitted — Latest diff uploaded
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.