2
0
Эх сурвалжийг харах

Fixed #25417 -- Added a field check for invalid default values.

Simon Charette 9 жил өмнө
parent
commit
71ebcb85b9

+ 17 - 0
django/db/models/fields/__init__.py

@@ -207,6 +207,7 @@ class Field(RegisterLookupMixin):
         errors = []
         errors.extend(self._check_field_name())
         errors.extend(self._check_choices())
+        errors.extend(self._check_default())
         errors.extend(self._check_db_index())
         errors.extend(self._check_null_allowed_for_primary_keys())
         errors.extend(self._check_backend_specific_checks(**kwargs))
@@ -283,6 +284,22 @@ class Field(RegisterLookupMixin):
         else:
             return []
 
+    def _check_default(self):
+        if self.has_default():
+            default = self.get_default()
+            try:
+                self.clean(default, None)
+            except exceptions.ValidationError as messages:
+                return [
+                    checks.Error(
+                        "Invalid 'default' value: %s" % message,
+                        hint=None,
+                        obj=self,
+                        id='fields.E008',
+                    ) for message in messages
+                ]
+        return []
+
     def _check_db_index(self):
         if self.db_index not in (None, True, False):
             return [

+ 1 - 0
docs/ref/checks.txt

@@ -140,6 +140,7 @@ Fields
   human readable name)`` tuples.
 * **fields.E006**: ``db_index`` must be ``None``, ``True`` or ``False``.
 * **fields.E007**: Primary keys must not have ``null=True``.
+* **fields.E008**: Invalid ``default`` value.
 * **fields.E100**: ``AutoField``\s must set primary_key=True.
 * **fields.E110**: ``BooleanField``\s do not accept null values.
 * **fields.E120**: ``CharField``\s must define a ``max_length`` attribute.

+ 3 - 0
docs/releases/1.9.txt

@@ -512,6 +512,9 @@ Models
 
 * ``connection.queries`` shows queries with substituted parameters on SQLite.
 
+* Added a new model field check that makes sure
+  :attr:`~django.db.models.Field.default` is a valid value.
+
 CSRF
 ^^^^
 

+ 68 - 0
tests/invalid_models_tests/test_ordinary_fields.py

@@ -1,6 +1,7 @@
 # -*- encoding: utf-8 -*-
 from __future__ import unicode_literals
 
+import decimal
 import unittest
 
 from django.core.checks import Error, Warning as DjangoWarning
@@ -64,6 +65,22 @@ class BooleanFieldTests(IsolatedModelsTestCase):
         ]
         self.assertEqual(errors, expected)
 
+    def test_invalid_default(self):
+        class Model(models.Model):
+            field = models.BooleanField(default='invalid')
+
+        field = Model._meta.get_field('field')
+        errors = field.check()
+        expected = [
+            Error(
+                "Invalid 'default' value: 'invalid' value must be either True or False.",
+                hint=None,
+                obj=field,
+                id='fields.E008',
+            ),
+        ]
+        self.assertEqual(errors, expected)
+
 
 class CharFieldTests(IsolatedModelsTestCase, TestCase):
 
@@ -215,6 +232,22 @@ class CharFieldTests(IsolatedModelsTestCase, TestCase):
         ]
         self.assertEqual(errors, expected)
 
+    def test_invalid_default(self):
+        class Model(models.Model):
+            field = models.CharField(max_length=10, default=None)
+
+        field = Model._meta.get_field('field')
+        errors = field.check()
+        expected = [
+            Error(
+                "Invalid 'default' value: This field cannot be null.",
+                hint=None,
+                obj=field,
+                id='fields.E008',
+            ),
+        ]
+        self.assertEqual(errors, expected)
+
 
 class DateFieldTests(IsolatedModelsTestCase, TestCase):
 
@@ -281,6 +314,25 @@ class DateFieldTests(IsolatedModelsTestCase, TestCase):
     def test_fix_default_value_tz(self):
         self.test_fix_default_value()
 
+    def test_invalid_default(self):
+        class Model(models.Model):
+            field = models.DateField(default='invalid')
+
+        field = Model._meta.get_field('field')
+        errors = field.check()
+        message = (
+            "Invalid 'default' value: 'invalid' value has an invalid date format. It must be in YYYY-MM-DD format."
+        )
+        expected = [
+            Error(
+                message,
+                hint=None,
+                obj=field,
+                id='fields.E008',
+            ),
+        ]
+        self.assertEqual(errors, expected)
+
 
 class DateTimeFieldTests(IsolatedModelsTestCase, TestCase):
 
@@ -419,6 +471,22 @@ class DecimalFieldTests(IsolatedModelsTestCase):
         expected = []
         self.assertEqual(errors, expected)
 
+    def test_invalid_default(self):
+        class Model(models.Model):
+            field = models.DecimalField(max_digits=3, decimal_places=2, default=decimal.Decimal('20.00'))
+
+        field = Model._meta.get_field('field')
+        errors = field.check()
+        expected = [
+            Error(
+                "Invalid 'default' value: Ensure that there are no more than 3 digits in total.",
+                hint=None,
+                obj=field,
+                id='fields.E008',
+            ),
+        ]
+        self.assertEqual(errors, expected)
+
 
 class FileFieldTests(IsolatedModelsTestCase):