Skip to content

Commit 6d38abb

Browse files
committed
Limit SmallerIntegerFields to 32 bit values
1 parent d2f18aa commit 6d38abb

File tree

4 files changed

+45
-7
lines changed

4 files changed

+45
-7
lines changed

django_mongodb_backend/operations.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,15 @@ def explain_query_prefix(self, format=None, **options):
256256
return validated_options
257257

258258
def integer_field_range(self, internal_type):
259-
# MongODB doesn't enforce any integer constraints, but it supports
260-
# integers up to 64 bits.
261-
if internal_type in {
262-
"PositiveBigIntegerField",
263-
"PositiveIntegerField",
264-
"PositiveSmallIntegerField",
265-
}:
259+
# MongoDB doesn't enforce any integer constraints, but the
260+
# SmallIntegerFields use "int" for unique constraints which is limited
261+
# to 32 bits.
262+
if internal_type == "PositiveSmallIntegerField":
263+
return (0, 2147483647)
264+
if internal_type == "SmallIntegerField":
265+
return (-2147483648, 2147483647)
266+
# Other fields use "long" which supports up to 64 bits.
267+
if internal_type in {"PositiveBigIntegerField", "PositiveIntegerField"}:
266268
return (0, 9223372036854775807)
267269
return (-9223372036854775808, 9223372036854775807)
268270

docs/source/ref/models/fields.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ A few notes about some of the other fields:
2020
(rather than microsecond like most other databases), and correspondingly,
2121
:class:`~django.db.models.DurationField` stores milliseconds rather than
2222
microseconds.
23+
- :class:`~django.db.models.SmallIntegerField` and
24+
:class:`~django.db.models.PositiveSmallIntegerField` support 32 bit values
25+
(ranges ``(-2147483648, 2147483647)`` and ``(0, 2147483647)``, respectively),
26+
validated by forms and model validation. Be careful because MongoDB doesn't
27+
prohibit inserting values outside of the supported range and unique
28+
constraints don't work for values outside of the 32-bit range of the BSON
29+
``int`` type.
2330

2431
MongoDB-specific model fields
2532
=============================

docs/source/releases/5.2.x.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ New features
2121
Backwards incompatible changes
2222
------------------------------
2323

24+
- :class:`django.db.models.SmallIntegerField` and
25+
:class:`django.db.models.PositiveSmallIntegerField` are now limited to 32 bit
26+
values in forms and model validation.
2427
- Removed support for database caching as the MongoDB security team considers the cache
2528
backend's ``pickle`` encoding of cached values a vulnerability. If an attacker
2629
compromises the database, they could run arbitrary commands on the application

tests/model_fields_/test_integerfield.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.core.exceptions import ValidationError
12
from django.db import IntegrityError
23
from django.test import TestCase
34

@@ -30,9 +31,22 @@ def test_unique_min_value(self):
3031
with self.assertRaises(IntegrityError):
3132
UniqueIntegers.objects.create(small=self.min_value)
3233

34+
def test_validate_max_value(self):
35+
UniqueIntegers(small=self.max_value).full_clean() # no error
36+
msg = "{'small': ['Ensure this value is less than or equal to 2147483647.']"
37+
with self.assertRaisesMessage(ValidationError, msg):
38+
UniqueIntegers(small=self.max_value + 1).full_clean()
39+
40+
def test_validate_min_value(self):
41+
UniqueIntegers(small=self.min_value).full_clean() # no error
42+
msg = "{'small': ['Ensure this value is greater than or equal to -2147483648.']"
43+
with self.assertRaisesMessage(ValidationError, msg):
44+
UniqueIntegers(small=self.min_value - 1).full_clean()
45+
3346

3447
class PositiveSmallIntegerFieldTests(TestCase):
3548
max_value = 2**31 - 1
49+
min_value = 0
3650

3751
def test_unique_max_value(self):
3852
"""
@@ -47,3 +61,15 @@ def test_unique_max_value(self):
4761

4862
# test_unique_min_value isn't needed since PositiveSmallIntegerField has a
4963
# limit of zero (enforced only in forms and model validation).
64+
65+
def test_validate_max_value(self):
66+
UniqueIntegers(positive_small=self.max_value).full_clean() # no error
67+
msg = "{'positive_small': ['Ensure this value is less than or equal to 2147483647.']"
68+
with self.assertRaisesMessage(ValidationError, msg):
69+
UniqueIntegers(positive_small=self.max_value + 1).full_clean()
70+
71+
def test_validate_min_value(self):
72+
UniqueIntegers(positive_small=self.min_value).full_clean() # no error
73+
msg = "{'positive_small': ['Ensure this value is greater than or equal to 0.']"
74+
with self.assertRaisesMessage(ValidationError, msg):
75+
UniqueIntegers(positive_small=self.min_value - 1).full_clean()

0 commit comments

Comments
 (0)