From 1c34b8716afde049f95ad1c72c2f8e148f826662 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Sun, 28 Dec 2025 19:21:49 +0100 Subject: [PATCH] Refs #24920 -- Made DecimalField system checks database dependent. Thanks Tim Graham for the suggestion. --- django/db/models/fields/__init__.py | 103 ++++++++++-------- .../test_ordinary_fields.py | 12 +- 2 files changed, 63 insertions(+), 52 deletions(-) diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 343e382b0516..831315ba6a92 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1715,10 +1715,11 @@ def __init__( def check(self, **kwargs): errors = super().check(**kwargs) + databases = kwargs.get("databases") or [] digits_errors = [ - *self._check_decimal_places(), - *self._check_max_digits(), + *self._check_decimal_places(databases), + *self._check_max_digits(databases), ] if not digits_errors: errors.extend(self._check_decimal_places_and_max_digits(**kwargs)) @@ -1726,29 +1727,34 @@ def check(self, **kwargs): errors.extend(digits_errors) return errors - def _check_decimal_places(self): + def _check_decimal_places(self, databases): if self.decimal_places is None: - if ( - not connection.features.supports_no_precision_decimalfield - and "supports_no_precision_decimalfield" - not in self.model._meta.required_db_features - ): - return [ - checks.Error( - "DecimalFields must define a 'decimal_places' attribute.", - obj=self, - id="fields.E130", - ) - ] - elif self.max_digits is not None: - return [ - checks.Error( - "DecimalField’s max_digits and decimal_places must both " - "be defined or both omitted.", - obj=self, - id="fields.E135", - ), - ] + for db in databases: + if not router.allow_migrate_model(db, self.model): + continue + connection = connections[db] + + if ( + not connection.features.supports_no_precision_decimalfield + and "supports_no_precision_decimalfield" + not in self.model._meta.required_db_features + ): + return [ + checks.Error( + "DecimalFields must define a 'decimal_places' attribute.", + obj=self, + id="fields.E130", + ) + ] + elif self.max_digits is not None: + return [ + checks.Error( + "DecimalField’s max_digits and decimal_places must both " + "be defined or both omitted.", + obj=self, + id="fields.E135", + ), + ] else: try: decimal_places = int(self.decimal_places) @@ -1764,29 +1770,34 @@ def _check_decimal_places(self): ] return [] - def _check_max_digits(self): + def _check_max_digits(self, databases): if self.max_digits is None: - if ( - not connection.features.supports_no_precision_decimalfield - and "supports_no_precision_decimalfield" - not in self.model._meta.required_db_features - ): - return [ - checks.Error( - "DecimalFields must define a 'max_digits' attribute.", - obj=self, - id="fields.E132", - ) - ] - elif self.decimal_places is not None: - return [ - checks.Error( - "DecimalField’s max_digits and decimal_places must both " - "be defined or both omitted.", - obj=self, - id="fields.E135", - ), - ] + for db in databases: + if not router.allow_migrate_model(db, self.model): + continue + connection = connections[db] + + if ( + not connection.features.supports_no_precision_decimalfield + and "supports_no_precision_decimalfield" + not in self.model._meta.required_db_features + ): + return [ + checks.Error( + "DecimalFields must define a 'max_digits' attribute.", + obj=self, + id="fields.E132", + ) + ] + elif self.decimal_places is not None: + return [ + checks.Error( + "DecimalField’s max_digits and decimal_places must both " + "be defined or both omitted.", + obj=self, + id="fields.E135", + ), + ] else: try: max_digits = int(self.max_digits) diff --git a/tests/invalid_models_tests/test_ordinary_fields.py b/tests/invalid_models_tests/test_ordinary_fields.py index e2ce74c67322..f445ec83b870 100644 --- a/tests/invalid_models_tests/test_ordinary_fields.py +++ b/tests/invalid_models_tests/test_ordinary_fields.py @@ -620,7 +620,7 @@ class Model(models.Model): id="fields.E132", ), ] - self.assertEqual(field.check(), expected) + self.assertEqual(field.check(databases=self.databases), expected) def test_both_attributes_omitted_required_db_features(self): class Model(models.Model): @@ -639,7 +639,7 @@ class Model(models.Model): field = Model._meta.get_field("field") self.assertEqual( - field.check(), + field.check(databases=self.databases), [ Error( "DecimalField’s max_digits and decimal_places must both " @@ -657,7 +657,7 @@ class Model(models.Model): field = Model._meta.get_field("field") self.assertEqual( - field.check(), + field.check(databases=self.databases), [ Error( "DecimalField’s max_digits and decimal_places must both " @@ -674,7 +674,7 @@ class Model(models.Model): field = Model._meta.get_field("field") self.assertEqual( - field.check(), + field.check(databases=self.databases), [ Error( "'decimal_places' must be a non-negative integer.", @@ -695,7 +695,7 @@ class Model(models.Model): field = Model._meta.get_field("field") self.assertEqual( - field.check(), + field.check(databases=self.databases), [ Error( "'decimal_places' must be a non-negative integer.", @@ -731,7 +731,7 @@ class Model(models.Model): field = models.DecimalField(max_digits=10, decimal_places=10) field = Model._meta.get_field("field") - self.assertEqual(field.check(), []) + self.assertEqual(field.check(databases=self.databases), []) @isolate_apps("invalid_models_tests")