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

This commit is contained in:
Simon Charette 2015-09-17 11:15:43 -04:00
parent 75ed590032
commit 71ebcb85b9
4 changed files with 89 additions and 0 deletions

View File

@ -207,6 +207,7 @@ class Field(RegisterLookupMixin):
errors = [] errors = []
errors.extend(self._check_field_name()) errors.extend(self._check_field_name())
errors.extend(self._check_choices()) errors.extend(self._check_choices())
errors.extend(self._check_default())
errors.extend(self._check_db_index()) errors.extend(self._check_db_index())
errors.extend(self._check_null_allowed_for_primary_keys()) errors.extend(self._check_null_allowed_for_primary_keys())
errors.extend(self._check_backend_specific_checks(**kwargs)) errors.extend(self._check_backend_specific_checks(**kwargs))
@ -283,6 +284,22 @@ class Field(RegisterLookupMixin):
else: else:
return [] 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): def _check_db_index(self):
if self.db_index not in (None, True, False): if self.db_index not in (None, True, False):
return [ return [

View File

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

View File

@ -512,6 +512,9 @@ Models
* ``connection.queries`` shows queries with substituted parameters on SQLite. * ``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 CSRF
^^^^ ^^^^

View File

@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import decimal
import unittest import unittest
from django.core.checks import Error, Warning as DjangoWarning from django.core.checks import Error, Warning as DjangoWarning
@ -64,6 +65,22 @@ class BooleanFieldTests(IsolatedModelsTestCase):
] ]
self.assertEqual(errors, expected) 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): class CharFieldTests(IsolatedModelsTestCase, TestCase):
@ -215,6 +232,22 @@ class CharFieldTests(IsolatedModelsTestCase, TestCase):
] ]
self.assertEqual(errors, expected) 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): class DateFieldTests(IsolatedModelsTestCase, TestCase):
@ -281,6 +314,25 @@ class DateFieldTests(IsolatedModelsTestCase, TestCase):
def test_fix_default_value_tz(self): def test_fix_default_value_tz(self):
self.test_fix_default_value() 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): class DateTimeFieldTests(IsolatedModelsTestCase, TestCase):
@ -419,6 +471,22 @@ class DecimalFieldTests(IsolatedModelsTestCase):
expected = [] expected = []
self.assertEqual(errors, 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): class FileFieldTests(IsolatedModelsTestCase):