diff options
| author | Simon Charette <charette.s@gmail.com> | 2014-03-03 20:12:42 -0500 |
|---|---|---|
| committer | Simon Charette <charette.s@gmail.com> | 2014-03-25 14:31:54 -0400 |
| commit | 78211b13a51f2ada1c7beb81ff97ef11f9e239eb (patch) | |
| tree | 2bd0dd1116c06a3705f423d278ee8bf723128995 /django | |
| parent | 7eaf329ad38ff7ea6b47f1b0a3c20ca7a5ad079b (diff) | |
[1.7.x] Fixed #12030 -- Validate integer field range at the model level.
Thanks to @timgraham for the review.
Backport of 1506c71a95 from master
Diffstat (limited to 'django')
| -rw-r--r-- | django/db/backends/__init__.py | 18 | ||||
| -rw-r--r-- | django/db/backends/mysql/base.py | 6 | ||||
| -rw-r--r-- | django/db/backends/oracle/base.py | 9 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/base.py | 4 | ||||
| -rw-r--r-- | django/db/models/fields/__init__.py | 10 |
5 files changed, 47 insertions, 0 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index b274065a21..98dab13ba8 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -722,6 +722,16 @@ class BaseDatabaseOperations(object): """ compiler_module = "django.db.models.sql.compiler" + # Integer field safe ranges by `internal_type` as documented + # in docs/ref/models/fields.txt. + integer_field_ranges = { + 'SmallIntegerField': (-32768, 32767), + 'IntegerField': (-2147483648, 2147483647), + 'BigIntegerField': (-9223372036854775808, 9223372036854775807), + 'PositiveSmallIntegerField': (0, 32767), + 'PositiveIntegerField': (0, 2147483647), + } + def __init__(self, connection): self.connection = connection self._cache = None @@ -1206,6 +1216,14 @@ class BaseDatabaseOperations(object): """ return params + def integer_field_range(self, internal_type): + """ + Given an integer field internal type (e.g. 'PositiveIntegerField'), + returns a tuple of the (min_value, max_value) form representing the + range of the column type bound to the field. + """ + return self.integer_field_ranges[internal_type] + # Structure returned by the DB-API cursor.description interface (PEP 249) FieldInfo = namedtuple('FieldInfo', diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index e79f980e21..61a8ab72fc 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -223,6 +223,12 @@ class DatabaseFeatures(BaseDatabaseFeatures): class DatabaseOperations(BaseDatabaseOperations): compiler_module = "django.db.backends.mysql.compiler" + # MySQL stores positive fields as UNSIGNED ints. + integer_field_ranges = dict(BaseDatabaseOperations.integer_field_ranges, + PositiveSmallIntegerField=(0, 4294967295), + PositiveIntegerField=(0, 18446744073709551615), + ) + def date_extract_sql(self, lookup_type, field_name): # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html if lookup_type == 'week_day': diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 0c799055fb..830a8a9862 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -121,6 +121,15 @@ class DatabaseFeatures(BaseDatabaseFeatures): class DatabaseOperations(BaseDatabaseOperations): compiler_module = "django.db.backends.oracle.compiler" + # Oracle uses NUMBER(11) and NUMBER(19) for integer fields. + integer_field_ranges = { + 'SmallIntegerField': (-99999999999, 99999999999), + 'IntegerField': (-99999999999, 99999999999), + 'BigIntegerField': (-9999999999999999999, 9999999999999999999), + 'PositiveSmallIntegerField': (0, 99999999999), + 'PositiveIntegerField': (0, 99999999999), + } + def autoinc_sql(self, table, column): # To simulate auto-incrementing primary keys in Oracle, we have to # create a sequence and a trigger. diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 3bb85e042d..9709e8449f 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -292,6 +292,10 @@ class DatabaseOperations(BaseDatabaseOperations): return 'django_power(%s)' % ','.join(sub_expressions) return super(DatabaseOperations, self).combine_expression(connector, sub_expressions) + def integer_field_range(self, internal_type): + # SQLite doesn't enforce any integer constraints + return (None, None) + class DatabaseWrapper(BaseDatabaseWrapper): vendor = 'sqlite' diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 8dfe7e79e5..4ebb6049b3 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1561,6 +1561,16 @@ class IntegerField(Field): } description = _("Integer") + def __init__(self, *args, **kwargs): + field_validators = kwargs.setdefault('validators', []) + internal_type = self.get_internal_type() + min_value, max_value = connection.ops.integer_field_range(internal_type) + if min_value is not None: + field_validators.append(validators.MinValueValidator(min_value)) + if max_value is not None: + field_validators.append(validators.MaxValueValidator(max_value)) + super(IntegerField, self).__init__(*args, **kwargs) + def get_prep_value(self, value): value = super(IntegerField, self).get_prep_value(value) if value is None: |
