summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2015-09-17 11:15:43 -0400
committerSimon Charette <charette.s@gmail.com>2015-09-18 14:31:36 -0400
commit71ebcb85b931f43865df5b322b2cf06d3da23f69 (patch)
treef0030999def3b0b4c6996ebd6175aafa300f371c
parent75ed5900321d170debef4ac452b8b3cf8a1c2384 (diff)
Fixed #25417 -- Added a field check for invalid default values.
-rw-r--r--django/db/models/fields/__init__.py17
-rw-r--r--docs/ref/checks.txt1
-rw-r--r--docs/releases/1.9.txt3
-rw-r--r--tests/invalid_models_tests/test_ordinary_fields.py68
4 files changed, 89 insertions, 0 deletions
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 992db81b34..a210ffc0b7 100644
--- a/django/db/models/fields/__init__.py
+++ b/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 [
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index 31f9a297cd..39f3a06089 100644
--- a/docs/ref/checks.txt
+++ b/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.
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index 810d619261..30f812c4d9 100644
--- a/docs/releases/1.9.txt
+++ b/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
^^^^
diff --git a/tests/invalid_models_tests/test_ordinary_fields.py b/tests/invalid_models_tests/test_ordinary_fields.py
index 033970aae4..9bde621ed4 100644
--- a/tests/invalid_models_tests/test_ordinary_fields.py
+++ b/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):