summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiederik van der Boor <vdboor@edoburu.nl>2017-07-13 13:55:23 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-08-05 08:41:29 +0200
commit25f21bd2376603c8e233a0a0e5a726a0fdfdd33e (patch)
tree4c75092f7ee29fff214a3f7c40ac00dd424afc04
parent1af469e67fd3928a4b01722d4706c066000014e9 (diff)
Fixed #28393 -- Added helpful error messages for invalid AutoField/FloatField/IntegerField values.
Co-authored-by: Diederik van der Boor <vdboor@edoburu.nl> Co-authored-by: Nick Pope <nick.pope@flightdataservices.com>
-rw-r--r--django/db/models/fields/__init__.py21
-rw-r--r--tests/model_fields/models.py12
-rw-r--r--tests/model_fields/test_autofield.py32
-rw-r--r--tests/model_fields/test_floatfield.py17
-rw-r--r--tests/model_fields/test_integerfield.py17
-rw-r--r--tests/queries/tests.py2
6 files changed, 97 insertions, 4 deletions
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index ff686e4f62..94effe437f 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -964,7 +964,12 @@ class AutoField(Field):
value = super().get_prep_value(value)
if value is None or isinstance(value, OuterRef):
return value
- return int(value)
+ try:
+ return int(value)
+ except (TypeError, ValueError) as e:
+ raise e.__class__(
+ "Field '%s' expected a number but got %r." % (self.name, value),
+ ) from e
def contribute_to_class(self, cls, name, **kwargs):
assert not cls._meta.auto_field, "Model %s can't have more than one AutoField." % cls._meta.label
@@ -1745,7 +1750,12 @@ class FloatField(Field):
value = super().get_prep_value(value)
if value is None:
return None
- return float(value)
+ try:
+ return float(value)
+ except (TypeError, ValueError) as e:
+ raise e.__class__(
+ "Field '%s' expected a number but got %r." % (self.name, value),
+ ) from e
def get_internal_type(self):
return "FloatField"
@@ -1827,7 +1837,12 @@ class IntegerField(Field):
value = super().get_prep_value(value)
if value is None:
return None
- return int(value)
+ try:
+ return int(value)
+ except (TypeError, ValueError) as e:
+ raise e.__class__(
+ "Field '%s' expected a number but got %r." % (self.name, value),
+ ) from e
def get_internal_type(self):
return "IntegerField"
diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py
index cbf3ec26ea..98b32d0c1e 100644
--- a/tests/model_fields/models.py
+++ b/tests/model_fields/models.py
@@ -92,6 +92,18 @@ class UnicodeSlugField(models.Model):
s = models.SlugField(max_length=255, allow_unicode=True)
+class AutoModel(models.Model):
+ value = models.AutoField(primary_key=True)
+
+
+class BigAutoModel(models.Model):
+ value = models.BigAutoField(primary_key=True)
+
+
+class SmallAutoModel(models.Model):
+ value = models.SmallAutoField(primary_key=True)
+
+
class SmallIntegerModel(models.Model):
value = models.SmallIntegerField()
diff --git a/tests/model_fields/test_autofield.py b/tests/model_fields/test_autofield.py
new file mode 100644
index 0000000000..73220ae62b
--- /dev/null
+++ b/tests/model_fields/test_autofield.py
@@ -0,0 +1,32 @@
+from django.test import TestCase
+
+from .models import AutoModel, BigAutoModel, SmallAutoModel
+
+
+class AutoFieldTests(TestCase):
+ model = AutoModel
+
+ def test_invalid_value(self):
+ tests = [
+ (TypeError, ()),
+ (TypeError, []),
+ (TypeError, {}),
+ (TypeError, set()),
+ (TypeError, object()),
+ (TypeError, complex()),
+ (ValueError, 'non-numeric string'),
+ (ValueError, b'non-numeric byte-string'),
+ ]
+ for exception, value in tests:
+ with self.subTest(value=value):
+ msg = "Field 'value' expected a number but got %r." % (value,)
+ with self.assertRaisesMessage(exception, msg):
+ self.model.objects.create(value=value)
+
+
+class BigAutoFieldTests(AutoFieldTests):
+ model = BigAutoModel
+
+
+class SmallAutoFieldTests(AutoFieldTests):
+ model = SmallAutoModel
diff --git a/tests/model_fields/test_floatfield.py b/tests/model_fields/test_floatfield.py
index 481925cf11..856197cd6e 100644
--- a/tests/model_fields/test_floatfield.py
+++ b/tests/model_fields/test_floatfield.py
@@ -31,3 +31,20 @@ class TestFloatField(TestCase):
obj.size = obj
with self.assertRaisesMessage(TypeError, msg):
obj.save()
+
+ def test_invalid_value(self):
+ tests = [
+ (TypeError, ()),
+ (TypeError, []),
+ (TypeError, {}),
+ (TypeError, set()),
+ (TypeError, object()),
+ (TypeError, complex()),
+ (ValueError, 'non-numeric string'),
+ (ValueError, b'non-numeric byte-string'),
+ ]
+ for exception, value in tests:
+ with self.subTest(value):
+ msg = "Field 'size' expected a number but got %r." % (value,)
+ with self.assertRaisesMessage(exception, msg):
+ FloatModel.objects.create(size=value)
diff --git a/tests/model_fields/test_integerfield.py b/tests/model_fields/test_integerfield.py
index 626b67b00b..c72cb48015 100644
--- a/tests/model_fields/test_integerfield.py
+++ b/tests/model_fields/test_integerfield.py
@@ -137,6 +137,23 @@ class IntegerFieldTests(TestCase):
instance = self.model.objects.get(value='10')
self.assertEqual(instance.value, 10)
+ def test_invalid_value(self):
+ tests = [
+ (TypeError, ()),
+ (TypeError, []),
+ (TypeError, {}),
+ (TypeError, set()),
+ (TypeError, object()),
+ (TypeError, complex()),
+ (ValueError, 'non-numeric string'),
+ (ValueError, b'non-numeric byte-string'),
+ ]
+ for exception, value in tests:
+ with self.subTest(value):
+ msg = "Field 'value' expected a number but got %r." % (value,)
+ with self.assertRaisesMessage(exception, msg):
+ self.model.objects.create(value=value)
+
class SmallIntegerFieldTests(IntegerFieldTests):
model = SmallIntegerModel
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 6d3dcbdb1f..8339c52a02 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -3853,7 +3853,7 @@ class TestTicket24279(TestCase):
class TestInvalidValuesRelation(SimpleTestCase):
def test_invalid_values(self):
- msg = "invalid literal for int() with base 10: 'abc'"
+ msg = "Field 'id' expected a number but got 'abc'."
with self.assertRaisesMessage(ValueError, msg):
Annotation.objects.filter(tag='abc')
with self.assertRaisesMessage(ValueError, msg):