Fixed #25417 -- Added a field check for invalid default values.
This commit is contained in:
parent
75ed590032
commit
71ebcb85b9
|
@ -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 [
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue