Browse Source

Refs #35234 -- Deprecated CheckConstraint.check in favor of .condition.

Once the deprecation period ends CheckConstraint.check() can become the
documented method that performs system checks for BaseConstraint
subclasses.
Simon Charette 1 year ago
parent
commit
daf7d482db

+ 49 - 14
django/db/models/constraints.py

@@ -134,13 +134,30 @@ class BaseConstraint:
 
 
 class CheckConstraint(BaseConstraint):
+    # RemovedInDjango60Warning: when the deprecation ends, replace with
+    # def __init__(
+    #  self, *, condition, name, violation_error_code=None, violation_error_message=None
+    # )
     def __init__(
-        self, *, check, name, violation_error_code=None, violation_error_message=None
+        self,
+        *,
+        name,
+        condition=None,
+        check=None,
+        violation_error_code=None,
+        violation_error_message=None,
     ):
-        self.check = check
-        if not getattr(check, "conditional", False):
+        if check is not None:
+            warnings.warn(
+                "CheckConstraint.check is deprecated in favor of `.condition`.",
+                RemovedInDjango60Warning,
+                stacklevel=2,
+            )
+            condition = check
+        self.condition = condition
+        if not getattr(condition, "conditional", False):
             raise TypeError(
-                "CheckConstraint.check must be a Q instance or boolean expression."
+                "CheckConstraint.condition must be a Q instance or boolean expression."
             )
         super().__init__(
             name=name,
@@ -148,6 +165,24 @@ class CheckConstraint(BaseConstraint):
             violation_error_message=violation_error_message,
         )
 
+    def _get_check(self):
+        warnings.warn(
+            "CheckConstraint.check is deprecated in favor of `.condition`.",
+            RemovedInDjango60Warning,
+            stacklevel=2,
+        )
+        return self.condition
+
+    def _set_check(self, value):
+        warnings.warn(
+            "CheckConstraint.check is deprecated in favor of `.condition`.",
+            RemovedInDjango60Warning,
+            stacklevel=2,
+        )
+        self.condition = value
+
+    check = property(_get_check, _set_check)
+
     def _check(self, model, connection):
         errors = []
         if not (
@@ -167,10 +202,10 @@ class CheckConstraint(BaseConstraint):
             )
         else:
             references = set()
-            check = self.check
-            if isinstance(check, Q):
-                references.update(model._get_expr_references(check))
-            if any(isinstance(expr, RawSQL) for expr in check.flatten()):
+            condition = self.condition
+            if isinstance(condition, Q):
+                references.update(model._get_expr_references(condition))
+            if any(isinstance(expr, RawSQL) for expr in condition.flatten()):
                 errors.append(
                     checks.Warning(
                         f"Check constraint {self.name!r} contains RawSQL() expression "
@@ -185,7 +220,7 @@ class CheckConstraint(BaseConstraint):
 
     def _get_check_sql(self, model, schema_editor):
         query = Query(model=model, alias_cols=False)
-        where = query.build_where(self.check)
+        where = query.build_where(self.condition)
         compiler = query.get_compiler(connection=schema_editor.connection)
         sql, params = where.as_sql(compiler, schema_editor.connection)
         return sql % tuple(schema_editor.quote_value(p) for p in params)
@@ -204,7 +239,7 @@ class CheckConstraint(BaseConstraint):
     def validate(self, model, instance, exclude=None, using=DEFAULT_DB_ALIAS):
         against = instance._get_field_value_map(meta=model._meta, exclude=exclude)
         try:
-            if not Q(self.check).check(against, using=using):
+            if not Q(self.condition).check(against, using=using):
                 raise ValidationError(
                     self.get_violation_error_message(), code=self.violation_error_code
                 )
@@ -212,9 +247,9 @@ class CheckConstraint(BaseConstraint):
             pass
 
     def __repr__(self):
-        return "<%s: check=%s name=%s%s%s>" % (
+        return "<%s: condition=%s name=%s%s%s>" % (
             self.__class__.__qualname__,
-            self.check,
+            self.condition,
             repr(self.name),
             (
                 ""
@@ -233,7 +268,7 @@ class CheckConstraint(BaseConstraint):
         if isinstance(other, CheckConstraint):
             return (
                 self.name == other.name
-                and self.check == other.check
+                and self.condition == other.condition
                 and self.violation_error_code == other.violation_error_code
                 and self.violation_error_message == other.violation_error_message
             )
@@ -241,7 +276,7 @@ class CheckConstraint(BaseConstraint):
 
     def deconstruct(self):
         path, args, kwargs = super().deconstruct()
-        kwargs["check"] = self.check
+        kwargs["condition"] = self.condition
         return path, args, kwargs
 
 

+ 2 - 0
docs/internals/deprecation.txt

@@ -77,6 +77,8 @@ details on these changes.
 * ``django.urls.register_converter()`` will no longer allow overriding existing
   converters.
 
+* The ``check`` keyword argument of ``CheckConstraint`` will be removed.
+
 .. _deprecation-removed-in-5.1:
 
 5.1

+ 13 - 9
docs/ref/models/constraints.txt

@@ -26,7 +26,7 @@ option.
     (including ``name``) each time. To work around name collisions, part of the
     name may contain ``'%(app_label)s'`` and ``'%(class)s'``, which are
     replaced, respectively, by the lowercased app label and class name of the
-    concrete model. For example ``CheckConstraint(check=Q(age__gte=18),
+    concrete model. For example ``CheckConstraint(condition=Q(age__gte=18),
     name='%(app_label)s_%(class)s_is_adult')``.
 
 .. admonition:: Validation of Constraints
@@ -104,19 +104,19 @@ This method must be implemented by a subclass.
 ``CheckConstraint``
 ===================
 
-.. class:: CheckConstraint(*, check, name, violation_error_code=None, violation_error_message=None)
+.. class:: CheckConstraint(*, condition, name, violation_error_code=None, violation_error_message=None)
 
     Creates a check constraint in the database.
 
-``check``
----------
+``condition``
+-------------
 
-.. attribute:: CheckConstraint.check
+.. attribute:: CheckConstraint.condition
 
 A :class:`Q` object or boolean :class:`~django.db.models.Expression` that
-specifies the check you want the constraint to enforce.
+specifies the conditional check you want the constraint to enforce.
 
-For example, ``CheckConstraint(check=Q(age__gte=18), name='age_gte_18')``
+For example, ``CheckConstraint(condition=Q(age__gte=18), name='age_gte_18')``
 ensures the age field is never less than 18.
 
 .. admonition:: Expression order
@@ -127,7 +127,7 @@ ensures the age field is never less than 18.
     reasons. For example, use the following format if order matters::
 
         CheckConstraint(
-            check=Q(age__gte=18) & Q(expensive_check=condition),
+            condition=Q(age__gte=18) & Q(expensive_check=condition),
             name="age_gte_18_and_others",
         )
 
@@ -138,7 +138,11 @@ ensures the age field is never less than 18.
     to behave the same as check constraints validation. For example, if ``age``
     is a nullable field::
 
-        CheckConstraint(check=Q(age__gte=18) | Q(age__isnull=True), name="age_gte_18")
+        CheckConstraint(condition=Q(age__gte=18) | Q(age__isnull=True), name="age_gte_18")
+
+.. deprecated:: 5.1
+
+    The ``check`` attribute is deprecated in favor of ``condition``.
 
 ``UniqueConstraint``
 ====================

+ 1 - 1
docs/ref/models/options.txt

@@ -467,7 +467,7 @@ not be looking at your Django code. For example::
 
             class Meta:
                 constraints = [
-                    models.CheckConstraint(check=models.Q(age__gte=18), name="age_gte_18"),
+                    models.CheckConstraint(condition=models.Q(age__gte=18), name="age_gte_18"),
                 ]
 
 ``verbose_name``

+ 1 - 1
docs/releases/3.1.txt

@@ -388,7 +388,7 @@ Models
   ``OneToOneField`` emulates the behavior of the SQL constraint ``ON DELETE
   RESTRICT``.
 
-* :attr:`.CheckConstraint.check` now supports boolean expressions.
+* ``CheckConstraint.check`` now supports boolean expressions.
 
 * The :meth:`.RelatedManager.add`, :meth:`~.RelatedManager.create`, and
   :meth:`~.RelatedManager.set` methods now accept callables as values in the

+ 3 - 0
docs/releases/5.1.txt

@@ -422,6 +422,9 @@ Miscellaneous
 * Overriding existing converters with ``django.urls.register_converter()`` is
   deprecated.
 
+* The ``check`` keyword argument of ``CheckConstraint`` is deprecated in favor
+  of ``condition``.
+
 Features removed in 5.1
 =======================
 

+ 1 - 1
tests/admin_changelist/tests.py

@@ -1443,7 +1443,7 @@ class ChangeListTests(TestCase):
                             ["field_3", "related_4_id"],
                         )
                     ],
-                    models.CheckConstraint(check=models.Q(id__gt=0), name="foo"),
+                    models.CheckConstraint(condition=models.Q(id__gt=0), name="foo"),
                     models.UniqueConstraint(
                         fields=["field_5"],
                         condition=models.Q(id__gt=10),

+ 7 - 7
tests/check_framework/test_model_checks.py

@@ -287,8 +287,8 @@ class ConstraintNameTests(TestCase):
         class Model(models.Model):
             class Meta:
                 constraints = [
-                    models.CheckConstraint(check=models.Q(id__gt=0), name="foo"),
-                    models.CheckConstraint(check=models.Q(id__lt=100), name="foo"),
+                    models.CheckConstraint(condition=models.Q(id__gt=0), name="foo"),
+                    models.CheckConstraint(condition=models.Q(id__lt=100), name="foo"),
                 ]
 
         self.assertEqual(
@@ -303,7 +303,7 @@ class ConstraintNameTests(TestCase):
         )
 
     def test_collision_in_different_models(self):
-        constraint = models.CheckConstraint(check=models.Q(id__gt=0), name="foo")
+        constraint = models.CheckConstraint(condition=models.Q(id__gt=0), name="foo")
 
         class Model1(models.Model):
             class Meta:
@@ -328,7 +328,7 @@ class ConstraintNameTests(TestCase):
         class AbstractModel(models.Model):
             class Meta:
                 constraints = [
-                    models.CheckConstraint(check=models.Q(id__gt=0), name="foo")
+                    models.CheckConstraint(condition=models.Q(id__gt=0), name="foo")
                 ]
                 abstract = True
 
@@ -354,7 +354,7 @@ class ConstraintNameTests(TestCase):
             class Meta:
                 constraints = [
                     models.CheckConstraint(
-                        check=models.Q(id__gt=0), name="%(app_label)s_%(class)s_foo"
+                        condition=models.Q(id__gt=0), name="%(app_label)s_%(class)s_foo"
                     ),
                 ]
                 abstract = True
@@ -370,7 +370,7 @@ class ConstraintNameTests(TestCase):
     @modify_settings(INSTALLED_APPS={"append": "basic"})
     @isolate_apps("basic", "check_framework", kwarg_name="apps")
     def test_collision_across_apps(self, apps):
-        constraint = models.CheckConstraint(check=models.Q(id__gt=0), name="foo")
+        constraint = models.CheckConstraint(condition=models.Q(id__gt=0), name="foo")
 
         class Model1(models.Model):
             class Meta:
@@ -397,7 +397,7 @@ class ConstraintNameTests(TestCase):
     @isolate_apps("basic", "check_framework", kwarg_name="apps")
     def test_no_collision_across_apps_interpolation(self, apps):
         constraint = models.CheckConstraint(
-            check=models.Q(id__gt=0), name="%(app_label)s_%(class)s_foo"
+            condition=models.Q(id__gt=0), name="%(app_label)s_%(class)s_foo"
         )
 
         class Model1(models.Model):

+ 4 - 4
tests/constraints/models.py

@@ -12,15 +12,15 @@ class Product(models.Model):
         }
         constraints = [
             models.CheckConstraint(
-                check=models.Q(price__gt=models.F("discounted_price")),
+                condition=models.Q(price__gt=models.F("discounted_price")),
                 name="price_gt_discounted_price",
             ),
             models.CheckConstraint(
-                check=models.Q(price__gt=0),
+                condition=models.Q(price__gt=0),
                 name="%(app_label)s_%(class)s_price_gt_0",
             ),
             models.CheckConstraint(
-                check=models.Q(
+                condition=models.Q(
                     models.Q(unit__isnull=True) | models.Q(unit__in=["μg/mL", "ng/mL"])
                 ),
                 name="unicode_unit_list",
@@ -113,7 +113,7 @@ class AbstractModel(models.Model):
         }
         constraints = [
             models.CheckConstraint(
-                check=models.Q(age__gte=18),
+                condition=models.Q(age__gte=18),
                 name="%(app_label)s_%(class)s_adult",
             ),
         ]

+ 55 - 38
tests/constraints/tests.py

@@ -123,104 +123,108 @@ class CheckConstraintTests(TestCase):
         check1 = models.Q(price__gt=models.F("discounted_price"))
         check2 = models.Q(price__lt=models.F("discounted_price"))
         self.assertEqual(
-            models.CheckConstraint(check=check1, name="price"),
-            models.CheckConstraint(check=check1, name="price"),
+            models.CheckConstraint(condition=check1, name="price"),
+            models.CheckConstraint(condition=check1, name="price"),
+        )
+        self.assertEqual(
+            models.CheckConstraint(condition=check1, name="price"), mock.ANY
         )
-        self.assertEqual(models.CheckConstraint(check=check1, name="price"), mock.ANY)
         self.assertNotEqual(
-            models.CheckConstraint(check=check1, name="price"),
-            models.CheckConstraint(check=check1, name="price2"),
+            models.CheckConstraint(condition=check1, name="price"),
+            models.CheckConstraint(condition=check1, name="price2"),
         )
         self.assertNotEqual(
-            models.CheckConstraint(check=check1, name="price"),
-            models.CheckConstraint(check=check2, name="price"),
+            models.CheckConstraint(condition=check1, name="price"),
+            models.CheckConstraint(condition=check2, name="price"),
         )
-        self.assertNotEqual(models.CheckConstraint(check=check1, name="price"), 1)
+        self.assertNotEqual(models.CheckConstraint(condition=check1, name="price"), 1)
         self.assertNotEqual(
-            models.CheckConstraint(check=check1, name="price"),
+            models.CheckConstraint(condition=check1, name="price"),
             models.CheckConstraint(
-                check=check1, name="price", violation_error_message="custom error"
+                condition=check1, name="price", violation_error_message="custom error"
             ),
         )
         self.assertNotEqual(
             models.CheckConstraint(
-                check=check1, name="price", violation_error_message="custom error"
+                condition=check1, name="price", violation_error_message="custom error"
             ),
             models.CheckConstraint(
-                check=check1, name="price", violation_error_message="other custom error"
+                condition=check1,
+                name="price",
+                violation_error_message="other custom error",
             ),
         )
         self.assertEqual(
             models.CheckConstraint(
-                check=check1, name="price", violation_error_message="custom error"
+                condition=check1, name="price", violation_error_message="custom error"
             ),
             models.CheckConstraint(
-                check=check1, name="price", violation_error_message="custom error"
+                condition=check1, name="price", violation_error_message="custom error"
             ),
         )
         self.assertNotEqual(
-            models.CheckConstraint(check=check1, name="price"),
+            models.CheckConstraint(condition=check1, name="price"),
             models.CheckConstraint(
-                check=check1, name="price", violation_error_code="custom_code"
+                condition=check1, name="price", violation_error_code="custom_code"
             ),
         )
         self.assertEqual(
             models.CheckConstraint(
-                check=check1, name="price", violation_error_code="custom_code"
+                condition=check1, name="price", violation_error_code="custom_code"
             ),
             models.CheckConstraint(
-                check=check1, name="price", violation_error_code="custom_code"
+                condition=check1, name="price", violation_error_code="custom_code"
             ),
         )
 
     def test_repr(self):
         constraint = models.CheckConstraint(
-            check=models.Q(price__gt=models.F("discounted_price")),
+            condition=models.Q(price__gt=models.F("discounted_price")),
             name="price_gt_discounted_price",
         )
         self.assertEqual(
             repr(constraint),
-            "<CheckConstraint: check=(AND: ('price__gt', F(discounted_price))) "
+            "<CheckConstraint: condition=(AND: ('price__gt', F(discounted_price))) "
             "name='price_gt_discounted_price'>",
         )
 
     def test_repr_with_violation_error_message(self):
         constraint = models.CheckConstraint(
-            check=models.Q(price__lt=1),
+            condition=models.Q(price__lt=1),
             name="price_lt_one",
             violation_error_message="More than 1",
         )
         self.assertEqual(
             repr(constraint),
-            "<CheckConstraint: check=(AND: ('price__lt', 1)) name='price_lt_one' "
+            "<CheckConstraint: condition=(AND: ('price__lt', 1)) name='price_lt_one' "
             "violation_error_message='More than 1'>",
         )
 
     def test_repr_with_violation_error_code(self):
         constraint = models.CheckConstraint(
-            check=models.Q(price__lt=1),
+            condition=models.Q(price__lt=1),
             name="price_lt_one",
             violation_error_code="more_than_one",
         )
         self.assertEqual(
             repr(constraint),
-            "<CheckConstraint: check=(AND: ('price__lt', 1)) name='price_lt_one' "
+            "<CheckConstraint: condition=(AND: ('price__lt', 1)) name='price_lt_one' "
             "violation_error_code='more_than_one'>",
         )
 
     def test_invalid_check_types(self):
-        msg = "CheckConstraint.check must be a Q instance or boolean expression."
+        msg = "CheckConstraint.condition must be a Q instance or boolean expression."
         with self.assertRaisesMessage(TypeError, msg):
-            models.CheckConstraint(check=models.F("discounted_price"), name="check")
+            models.CheckConstraint(condition=models.F("discounted_price"), name="check")
 
     def test_deconstruction(self):
         check = models.Q(price__gt=models.F("discounted_price"))
         name = "price_gt_discounted_price"
-        constraint = models.CheckConstraint(check=check, name=name)
+        constraint = models.CheckConstraint(condition=check, name=name)
         path, args, kwargs = constraint.deconstruct()
         self.assertEqual(path, "django.db.models.CheckConstraint")
         self.assertEqual(args, ())
-        self.assertEqual(kwargs, {"check": check, "name": name})
+        self.assertEqual(kwargs, {"condition": check, "name": name})
 
     @skipUnlessDBFeature("supports_table_check_constraints")
     def test_database_constraint(self):
@@ -255,7 +259,7 @@ class CheckConstraintTests(TestCase):
 
     def test_validate(self):
         check = models.Q(price__gt=models.F("discounted_price"))
-        constraint = models.CheckConstraint(check=check, name="price")
+        constraint = models.CheckConstraint(condition=check, name="price")
         # Invalid product.
         invalid_product = Product(price=10, discounted_price=42)
         with self.assertRaises(ValidationError):
@@ -276,7 +280,7 @@ class CheckConstraintTests(TestCase):
     def test_validate_custom_error(self):
         check = models.Q(price__gt=models.F("discounted_price"))
         constraint = models.CheckConstraint(
-            check=check,
+            condition=check,
             name="price",
             violation_error_message="discount is fake",
             violation_error_code="fake_discount",
@@ -290,7 +294,7 @@ class CheckConstraintTests(TestCase):
 
     def test_validate_boolean_expressions(self):
         constraint = models.CheckConstraint(
-            check=models.expressions.ExpressionWrapper(
+            condition=models.expressions.ExpressionWrapper(
                 models.Q(price__gt=500) | models.Q(price__lt=500),
                 output_field=models.BooleanField(),
             ),
@@ -304,7 +308,7 @@ class CheckConstraintTests(TestCase):
 
     def test_validate_rawsql_expressions_noop(self):
         constraint = models.CheckConstraint(
-            check=models.expressions.RawSQL(
+            condition=models.expressions.RawSQL(
                 "price < %s OR price > %s",
                 (500, 500),
                 output_field=models.BooleanField(),
@@ -320,7 +324,7 @@ class CheckConstraintTests(TestCase):
     def test_validate_nullable_field_with_none(self):
         # Nullable fields should be considered valid on None values.
         constraint = models.CheckConstraint(
-            check=models.Q(price__gte=0),
+            condition=models.Q(price__gte=0),
             name="positive_price",
         )
         constraint.validate(Product, Product())
@@ -328,7 +332,7 @@ class CheckConstraintTests(TestCase):
     @skipIfDBFeature("supports_comparing_boolean_expr")
     def test_validate_nullable_field_with_isnull(self):
         constraint = models.CheckConstraint(
-            check=models.Q(price__gte=0) | models.Q(price__isnull=True),
+            condition=models.Q(price__gte=0) | models.Q(price__isnull=True),
             name="positive_price",
         )
         constraint.validate(Product, Product())
@@ -336,11 +340,11 @@ class CheckConstraintTests(TestCase):
     @skipUnlessDBFeature("supports_json_field")
     def test_validate_nullable_jsonfield(self):
         is_null_constraint = models.CheckConstraint(
-            check=models.Q(data__isnull=True),
+            condition=models.Q(data__isnull=True),
             name="nullable_data",
         )
         is_not_null_constraint = models.CheckConstraint(
-            check=models.Q(data__isnull=False),
+            condition=models.Q(data__isnull=False),
             name="nullable_data",
         )
         is_null_constraint.validate(JSONFieldModel, JSONFieldModel(data=None))
@@ -354,7 +358,7 @@ class CheckConstraintTests(TestCase):
 
     def test_validate_pk_field(self):
         constraint_with_pk = models.CheckConstraint(
-            check=~models.Q(pk=models.F("age")),
+            condition=~models.Q(pk=models.F("age")),
             name="pk_not_age_check",
         )
         constraint_with_pk.validate(ChildModel, ChildModel(pk=1, age=2))
@@ -369,7 +373,7 @@ class CheckConstraintTests(TestCase):
     def test_validate_jsonfield_exact(self):
         data = {"release": "5.0.2", "version": "stable"}
         json_exact_constraint = models.CheckConstraint(
-            check=models.Q(data__version="stable"),
+            condition=models.Q(data__version="stable"),
             name="only_stable_version",
         )
         json_exact_constraint.validate(JSONFieldModel, JSONFieldModel(data=data))
@@ -379,6 +383,19 @@ class CheckConstraintTests(TestCase):
         with self.assertRaisesMessage(ValidationError, msg):
             json_exact_constraint.validate(JSONFieldModel, JSONFieldModel(data=data))
 
+    def test_check_deprecation(self):
+        msg = "CheckConstraint.check is deprecated in favor of `.condition`."
+        condition = models.Q(foo="bar")
+        with self.assertWarnsRegex(RemovedInDjango60Warning, msg):
+            constraint = models.CheckConstraint(name="constraint", check=condition)
+        with self.assertWarnsRegex(RemovedInDjango60Warning, msg):
+            self.assertIs(constraint.check, condition)
+        other_condition = models.Q(something="else")
+        with self.assertWarnsRegex(RemovedInDjango60Warning, msg):
+            constraint.check = other_condition
+        with self.assertWarnsRegex(RemovedInDjango60Warning, msg):
+            self.assertIs(constraint.check, other_condition)
+
 
 class UniqueConstraintTests(TestCase):
     @classmethod

+ 1 - 1
tests/gis_tests/gis_migrations/test_operations.py

@@ -270,7 +270,7 @@ class OperationTests(OperationTestCase):
         Neighborhood = self.current_state.apps.get_model("gis", "Neighborhood")
         poly = Polygon(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)))
         constraint = models.CheckConstraint(
-            check=models.Q(geom=poly),
+            condition=models.Q(geom=poly),
             name="geom_within_constraint",
         )
         Neighborhood._meta.constraints = [constraint]

+ 1 - 1
tests/introspection/models.py

@@ -84,7 +84,7 @@ class CheckConstraintModel(models.Model):
         }
         constraints = [
             models.CheckConstraint(
-                name="up_votes_gte_0_check", check=models.Q(up_votes__gte=0)
+                name="up_votes_gte_0_check", condition=models.Q(up_votes__gte=0)
             ),
         ]
 

+ 25 - 18
tests/invalid_models_tests/test_models.py

@@ -1855,7 +1855,9 @@ class ConstraintsTests(TestCase):
 
             class Meta:
                 constraints = [
-                    models.CheckConstraint(check=models.Q(age__gte=18), name="is_adult")
+                    models.CheckConstraint(
+                        condition=models.Q(age__gte=18), name="is_adult"
+                    )
                 ]
 
         errors = Model.check(databases=self.databases)
@@ -1880,7 +1882,9 @@ class ConstraintsTests(TestCase):
             class Meta:
                 required_db_features = {"supports_table_check_constraints"}
                 constraints = [
-                    models.CheckConstraint(check=models.Q(age__gte=18), name="is_adult")
+                    models.CheckConstraint(
+                        condition=models.Q(age__gte=18), name="is_adult"
+                    )
                 ]
 
         self.assertEqual(Model.check(databases=self.databases), [])
@@ -1892,7 +1896,7 @@ class ConstraintsTests(TestCase):
                 constraints = [
                     models.CheckConstraint(
                         name="name",
-                        check=models.Q(missing_field=2),
+                        condition=models.Q(missing_field=2),
                     ),
                 ]
 
@@ -1919,7 +1923,7 @@ class ConstraintsTests(TestCase):
 
             class Meta:
                 constraints = [
-                    models.CheckConstraint(name="name", check=models.Q(parents=3)),
+                    models.CheckConstraint(name="name", condition=models.Q(parents=3)),
                 ]
 
         self.assertEqual(
@@ -1942,7 +1946,7 @@ class ConstraintsTests(TestCase):
                 constraints = [
                     models.CheckConstraint(
                         name="name",
-                        check=models.Q(model__isnull=True),
+                        condition=models.Q(model__isnull=True),
                     ),
                 ]
 
@@ -1964,7 +1968,7 @@ class ConstraintsTests(TestCase):
 
             class Meta:
                 constraints = [
-                    models.CheckConstraint(name="name", check=models.Q(m2m=2)),
+                    models.CheckConstraint(name="name", condition=models.Q(m2m=2)),
                 ]
 
         self.assertEqual(
@@ -1992,7 +1996,7 @@ class ConstraintsTests(TestCase):
                 constraints = [
                     models.CheckConstraint(
                         name="name",
-                        check=models.Q(fk_1_id=2) | models.Q(fk_2=2),
+                        condition=models.Q(fk_1_id=2) | models.Q(fk_2=2),
                     ),
                 ]
 
@@ -2007,7 +2011,7 @@ class ConstraintsTests(TestCase):
                 constraints = [
                     models.CheckConstraint(
                         name="name",
-                        check=models.Q(pk__gt=5) & models.Q(age__gt=models.F("pk")),
+                        condition=models.Q(pk__gt=5) & models.Q(age__gt=models.F("pk")),
                     ),
                 ]
 
@@ -2023,7 +2027,7 @@ class ConstraintsTests(TestCase):
 
             class Meta:
                 constraints = [
-                    models.CheckConstraint(name="name", check=models.Q(field1=1)),
+                    models.CheckConstraint(name="name", condition=models.Q(field1=1)),
                 ]
 
         self.assertEqual(
@@ -2053,20 +2057,21 @@ class ConstraintsTests(TestCase):
                 constraints = [
                     models.CheckConstraint(
                         name="name1",
-                        check=models.Q(
+                        condition=models.Q(
                             field1__lt=models.F("parent__field1")
                             + models.F("parent__field2")
                         ),
                     ),
                     models.CheckConstraint(
-                        name="name2", check=models.Q(name=Lower("parent__name"))
+                        name="name2", condition=models.Q(name=Lower("parent__name"))
                     ),
                     models.CheckConstraint(
-                        name="name3", check=models.Q(parent__field3=models.F("field1"))
+                        name="name3",
+                        condition=models.Q(parent__field3=models.F("field1")),
                     ),
                     models.CheckConstraint(
                         name="name4",
-                        check=models.Q(name=Lower("previous__name")),
+                        condition=models.Q(name=Lower("previous__name")),
                     ),
                 ]
 
@@ -2100,7 +2105,7 @@ class ConstraintsTests(TestCase):
                 constraints = [
                     models.CheckConstraint(
                         name="name",
-                        check=models.Q(
+                        condition=models.Q(
                             (
                                 models.Q(name="test")
                                 & models.Q(field1__lt=models.F("parent__field1"))
@@ -2136,16 +2141,18 @@ class ConstraintsTests(TestCase):
             class Meta:
                 required_db_features = {"supports_table_check_constraints"}
                 constraints = [
-                    models.CheckConstraint(check=models.Q(id__gt=0), name="q_check"),
                     models.CheckConstraint(
-                        check=models.ExpressionWrapper(
+                        condition=models.Q(id__gt=0), name="q_check"
+                    ),
+                    models.CheckConstraint(
+                        condition=models.ExpressionWrapper(
                             models.Q(price__gt=20),
                             output_field=models.BooleanField(),
                         ),
                         name="expression_wrapper_check",
                     ),
                     models.CheckConstraint(
-                        check=models.expressions.RawSQL(
+                        condition=models.expressions.RawSQL(
                             "id = 0",
                             params=(),
                             output_field=models.BooleanField(),
@@ -2153,7 +2160,7 @@ class ConstraintsTests(TestCase):
                         name="raw_sql_check",
                     ),
                     models.CheckConstraint(
-                        check=models.Q(
+                        condition=models.Q(
                             models.ExpressionWrapper(
                                 models.Q(
                                     models.expressions.RawSQL(

+ 10 - 9
tests/migrations/test_autodetector.py

@@ -287,7 +287,7 @@ class AutodetectorTests(BaseAutodetectorTests):
         {
             "constraints": [
                 models.CheckConstraint(
-                    check=models.Q(name__contains="Bob"), name="name_contains_bob"
+                    condition=models.Q(name__contains="Bob"), name="name_contains_bob"
                 )
             ]
         },
@@ -2756,14 +2756,15 @@ class AutodetectorTests(BaseAutodetectorTests):
             {
                 "constraints": [
                     models.CheckConstraint(
-                        check=models.Q(name__contains="Bob"), name="name_contains_bob"
+                        condition=models.Q(name__contains="Bob"),
+                        name="name_contains_bob",
                     )
                 ]
             },
         )
         changes = self.get_changes([], [author])
         constraint = models.CheckConstraint(
-            check=models.Q(name__contains="Bob"), name="name_contains_bob"
+            condition=models.Q(name__contains="Bob"), name="name_contains_bob"
         )
         # Right number of migrations?
         self.assertEqual(len(changes["otherapp"]), 1)
@@ -2789,7 +2790,7 @@ class AutodetectorTests(BaseAutodetectorTests):
         self.assertNumberMigrations(changes, "testapp", 1)
         self.assertOperationTypes(changes, "testapp", 0, ["AddConstraint"])
         added_constraint = models.CheckConstraint(
-            check=models.Q(name__contains="Bob"), name="name_contains_bob"
+            condition=models.Q(name__contains="Bob"), name="name_contains_bob"
         )
         self.assertOperationAttributes(
             changes, "testapp", 0, 0, model_name="author", constraint=added_constraint
@@ -2838,7 +2839,7 @@ class AutodetectorTests(BaseAutodetectorTests):
             {
                 "constraints": [
                     models.CheckConstraint(
-                        check=models.Q(type__in=book_types.keys()),
+                        condition=models.Q(type__in=book_types.keys()),
                         name="book_type_check",
                     ),
                 ],
@@ -2854,7 +2855,7 @@ class AutodetectorTests(BaseAutodetectorTests):
             {
                 "constraints": [
                     models.CheckConstraint(
-                        check=models.Q(("type__in", tuple(book_types))),
+                        condition=models.Q(("type__in", tuple(book_types))),
                         name="book_type_check",
                     ),
                 ],
@@ -4168,7 +4169,7 @@ class AutodetectorTests(BaseAutodetectorTests):
                 "order_with_respect_to": "book",
                 "constraints": [
                     models.CheckConstraint(
-                        check=models.Q(_order__gt=1), name="book_order_gt_1"
+                        condition=models.Q(_order__gt=1), name="book_order_gt_1"
                     ),
                 ],
             },
@@ -4191,7 +4192,7 @@ class AutodetectorTests(BaseAutodetectorTests):
                 "order_with_respect_to": "book",
                 "constraints": [
                     models.CheckConstraint(
-                        check=models.Q(_order__gt=1), name="book_order_gt_1"
+                        condition=models.Q(_order__gt=1), name="book_order_gt_1"
                     )
                 ],
             },
@@ -4241,7 +4242,7 @@ class AutodetectorTests(BaseAutodetectorTests):
                 {
                     "constraints": [
                         models.CheckConstraint(
-                            check=models.Q(_order__gt=1),
+                            condition=models.Q(_order__gt=1),
                             name="book_order_gt_1",
                         ),
                     ]

+ 11 - 11
tests/migrations/test_operations.py

@@ -441,7 +441,7 @@ class OperationTests(OperationTestBase):
     def test_create_model_with_constraint(self):
         where = models.Q(pink__gt=2)
         check_constraint = models.CheckConstraint(
-            check=where, name="test_constraint_pony_pink_gt_2"
+            condition=where, name="test_constraint_pony_pink_gt_2"
         )
         operation = migrations.CreateModel(
             "Pony",
@@ -484,13 +484,13 @@ class OperationTests(OperationTestBase):
     def test_create_model_with_boolean_expression_in_check_constraint(self):
         app_label = "test_crmobechc"
         rawsql_constraint = models.CheckConstraint(
-            check=models.expressions.RawSQL(
+            condition=models.expressions.RawSQL(
                 "price < %s", (1000,), output_field=models.BooleanField()
             ),
             name=f"{app_label}_price_lt_1000_raw",
         )
         wrapper_constraint = models.CheckConstraint(
-            check=models.expressions.ExpressionWrapper(
+            condition=models.expressions.ExpressionWrapper(
                 models.Q(price__gt=500) | models.Q(price__lt=500),
                 output_field=models.BooleanField(),
             ),
@@ -3858,7 +3858,7 @@ class OperationTests(OperationTestBase):
         project_state = self.set_up_test_model("test_addconstraint")
         gt_check = models.Q(pink__gt=2)
         gt_constraint = models.CheckConstraint(
-            check=gt_check, name="test_add_constraint_pony_pink_gt_2"
+            condition=gt_check, name="test_add_constraint_pony_pink_gt_2"
         )
         gt_operation = migrations.AddConstraint("Pony", gt_constraint)
         self.assertEqual(
@@ -3901,7 +3901,7 @@ class OperationTests(OperationTestBase):
         # Add another one.
         lt_check = models.Q(pink__lt=100)
         lt_constraint = models.CheckConstraint(
-            check=lt_check, name="test_add_constraint_pony_pink_lt_100"
+            condition=lt_check, name="test_add_constraint_pony_pink_lt_100"
         )
         lt_operation = migrations.AddConstraint("Pony", lt_constraint)
         lt_operation.state_forwards("test_addconstraint", new_state)
@@ -3981,8 +3981,8 @@ class OperationTests(OperationTestBase):
             ),
         ]
         for check, valid, invalid in checks:
-            with self.subTest(check=check, valid=valid, invalid=invalid):
-                constraint = models.CheckConstraint(check=check, name="constraint")
+            with self.subTest(condition=check, valid=valid, invalid=invalid):
+                constraint = models.CheckConstraint(condition=check, name="constraint")
                 operation = migrations.AddConstraint("Author", constraint)
                 to_state = from_state.clone()
                 operation.state_forwards(app_label, to_state)
@@ -4006,7 +4006,7 @@ class OperationTests(OperationTestBase):
         constraint_name = "add_constraint_or"
         from_state = self.set_up_test_model(app_label)
         check = models.Q(pink__gt=2, weight__gt=2) | models.Q(weight__lt=0)
-        constraint = models.CheckConstraint(check=check, name=constraint_name)
+        constraint = models.CheckConstraint(condition=check, name=constraint_name)
         operation = migrations.AddConstraint("Pony", constraint)
         to_state = from_state.clone()
         operation.state_forwards(app_label, to_state)
@@ -4040,7 +4040,7 @@ class OperationTests(OperationTestBase):
         ]
         from_state = self.apply_operations(app_label, ProjectState(), operations)
         constraint = models.CheckConstraint(
-            check=models.Q(read=(100 - models.F("unread"))),
+            condition=models.Q(read=(100 - models.F("unread"))),
             name="test_addconstraint_combinable_sum_100",
         )
         operation = migrations.AddConstraint("Book", constraint)
@@ -4058,11 +4058,11 @@ class OperationTests(OperationTestBase):
             "test_removeconstraint",
             constraints=[
                 models.CheckConstraint(
-                    check=models.Q(pink__gt=2),
+                    condition=models.Q(pink__gt=2),
                     name="test_remove_constraint_pony_pink_gt_2",
                 ),
                 models.CheckConstraint(
-                    check=models.Q(pink__lt=100),
+                    condition=models.Q(pink__lt=100),
                     name="test_remove_constraint_pony_pink_lt_100",
                 ),
             ],

+ 4 - 3
tests/migrations/test_optimizer.py

@@ -1208,7 +1208,7 @@ class OptimizerTests(SimpleTestCase):
 
     def test_add_remove_constraint(self):
         gt_constraint = models.CheckConstraint(
-            check=models.Q(pink__gt=2), name="constraint_pony_pink_gt_2"
+            condition=models.Q(pink__gt=2), name="constraint_pony_pink_gt_2"
         )
         self.assertOptimizesTo(
             [
@@ -1329,7 +1329,7 @@ class OptimizerTests(SimpleTestCase):
 
     def test_create_model_add_constraint(self):
         gt_constraint = models.CheckConstraint(
-            check=models.Q(weight__gt=0), name="pony_weight_gt_0"
+            condition=models.Q(weight__gt=0), name="pony_weight_gt_0"
         )
         self.assertOptimizesTo(
             [
@@ -1363,7 +1363,8 @@ class OptimizerTests(SimpleTestCase):
                     options={
                         "constraints": [
                             models.CheckConstraint(
-                                check=models.Q(weight__gt=0), name="pony_weight_gt_0"
+                                condition=models.Q(weight__gt=0),
+                                name="pony_weight_gt_0",
                             ),
                             models.UniqueConstraint(
                                 "weight", name="pony_weight_unique"

+ 3 - 1
tests/migrations/test_state.py

@@ -1887,7 +1887,9 @@ class ModelStateTests(SimpleTestCase):
 
             class Meta:
                 constraints = [
-                    models.CheckConstraint(check=models.Q(size__gt=1), name="size_gt_1")
+                    models.CheckConstraint(
+                        condition=models.Q(size__gt=1), name="size_gt_1"
+                    )
                 ]
 
         state = ModelState.from_model(ModelWithConstraints)

+ 9 - 9
tests/postgres_tests/test_constraints.py

@@ -59,7 +59,7 @@ class SchemaTests(PostgreSQLTestCase):
             constraint_name, self.get_constraints(RangesModel._meta.db_table)
         )
         constraint = CheckConstraint(
-            check=Q(ints__contained_by=NumericRange(10, 30)),
+            condition=Q(ints__contained_by=NumericRange(10, 30)),
             name=constraint_name,
         )
         with connection.schema_editor() as editor:
@@ -71,7 +71,7 @@ class SchemaTests(PostgreSQLTestCase):
 
     def test_check_constraint_array_contains(self):
         constraint = CheckConstraint(
-            check=Q(field__contains=[1]),
+            condition=Q(field__contains=[1]),
             name="array_contains",
         )
         msg = f"Constraint “{constraint.name}” is violated."
@@ -81,7 +81,7 @@ class SchemaTests(PostgreSQLTestCase):
 
     def test_check_constraint_array_length(self):
         constraint = CheckConstraint(
-            check=Q(field__len=1),
+            condition=Q(field__len=1),
             name="array_length",
         )
         msg = f"Constraint “{constraint.name}” is violated."
@@ -95,7 +95,7 @@ class SchemaTests(PostgreSQLTestCase):
             constraint_name, self.get_constraints(RangesModel._meta.db_table)
         )
         constraint = CheckConstraint(
-            check=Q(dates__contains=F("dates_inner")),
+            condition=Q(dates__contains=F("dates_inner")),
             name=constraint_name,
         )
         with connection.schema_editor() as editor:
@@ -119,7 +119,7 @@ class SchemaTests(PostgreSQLTestCase):
             constraint_name, self.get_constraints(RangesModel._meta.db_table)
         )
         constraint = CheckConstraint(
-            check=Q(timestamps__contains=F("timestamps_inner")),
+            condition=Q(timestamps__contains=F("timestamps_inner")),
             name=constraint_name,
         )
         with connection.schema_editor() as editor:
@@ -139,7 +139,7 @@ class SchemaTests(PostgreSQLTestCase):
 
     def test_check_constraint_range_contains(self):
         constraint = CheckConstraint(
-            check=Q(ints__contains=(1, 5)),
+            condition=Q(ints__contains=(1, 5)),
             name="ints_contains",
         )
         msg = f"Constraint “{constraint.name}” is violated."
@@ -148,7 +148,7 @@ class SchemaTests(PostgreSQLTestCase):
 
     def test_check_constraint_range_lower_upper(self):
         constraint = CheckConstraint(
-            check=Q(ints__startswith__gte=0) & Q(ints__endswith__lte=99),
+            condition=Q(ints__startswith__gte=0) & Q(ints__endswith__lte=99),
             name="ints_range_lower_upper",
         )
         msg = f"Constraint “{constraint.name}” is violated."
@@ -160,12 +160,12 @@ class SchemaTests(PostgreSQLTestCase):
 
     def test_check_constraint_range_lower_with_nulls(self):
         constraint = CheckConstraint(
-            check=Q(ints__isnull=True) | Q(ints__startswith__gte=0),
+            condition=Q(ints__isnull=True) | Q(ints__startswith__gte=0),
             name="ints_optional_positive_range",
         )
         constraint.validate(RangesModel, RangesModel())
         constraint = CheckConstraint(
-            check=Q(ints__startswith__gte=0),
+            condition=Q(ints__startswith__gte=0),
             name="ints_positive_range",
         )
         constraint.validate(RangesModel, RangesModel())

+ 2 - 2
tests/postgres_tests/test_operations.py

@@ -496,7 +496,7 @@ class AddConstraintNotValidTests(OperationTestBase):
     def test_add(self):
         table_name = f"{self.app_label}_pony"
         constraint_name = "pony_pink_gte_check"
-        constraint = CheckConstraint(check=Q(pink__gte=4), name=constraint_name)
+        constraint = CheckConstraint(condition=Q(pink__gte=4), name=constraint_name)
         operation = AddConstraintNotValid("Pony", constraint=constraint)
         project_state, new_state = self.make_test_state(self.app_label, operation)
         self.assertEqual(
@@ -549,7 +549,7 @@ class ValidateConstraintTests(OperationTestBase):
 
     def test_validate(self):
         constraint_name = "pony_pink_gte_check"
-        constraint = CheckConstraint(check=Q(pink__gte=4), name=constraint_name)
+        constraint = CheckConstraint(condition=Q(pink__gte=4), name=constraint_name)
         operation = AddConstraintNotValid("Pony", constraint=constraint)
         project_state, new_state = self.make_test_state(self.app_label, operation)
         Pony = new_state.apps.get_model(self.app_label, "Pony")

+ 6 - 4
tests/schema/tests.py

@@ -2791,7 +2791,7 @@ class SchemaTests(TransactionTestCase):
         self.isolated_local_models = [DurationModel]
         constraint_name = "duration_gte_5_minutes"
         constraint = CheckConstraint(
-            check=Q(duration__gt=datetime.timedelta(minutes=5)),
+            condition=Q(duration__gt=datetime.timedelta(minutes=5)),
             name=constraint_name,
         )
         DurationModel._meta.constraints = [constraint]
@@ -2821,7 +2821,7 @@ class SchemaTests(TransactionTestCase):
         self.isolated_local_models = [JSONConstraintModel]
         constraint_name = "check_only_stable_version"
         constraint = CheckConstraint(
-            check=Q(data__version="stable"),
+            condition=Q(data__version="stable"),
             name=constraint_name,
         )
         JSONConstraintModel._meta.constraints = [constraint]
@@ -2845,7 +2845,7 @@ class SchemaTests(TransactionTestCase):
             editor.create_model(Author)
         # Add the custom check constraint
         constraint = CheckConstraint(
-            check=Q(height__gte=0), name="author_height_gte_0_check"
+            condition=Q(height__gte=0), name="author_height_gte_0_check"
         )
         custom_constraint_name = constraint.name
         Author._meta.constraints = [constraint]
@@ -3256,7 +3256,9 @@ class SchemaTests(TransactionTestCase):
         "supports_column_check_constraints", "can_introspect_check_constraints"
     )
     def test_composed_check_constraint_with_fk(self):
-        constraint = CheckConstraint(check=Q(author__gt=0), name="book_author_check")
+        constraint = CheckConstraint(
+            condition=Q(author__gt=0), name="book_author_check"
+        )
         self._test_composed_constraint_with_fk(constraint)
 
     @skipUnlessDBFeature("allows_multiple_constraints_on_same_fields")

+ 1 - 1
tests/validation/models.py

@@ -173,7 +173,7 @@ class Product(models.Model):
         }
         constraints = [
             models.CheckConstraint(
-                check=models.Q(price__gt=models.F("discounted_price")),
+                condition=models.Q(price__gt=models.F("discounted_price")),
                 name="price_gt_discounted_price_validation",
             ),
         ]