mirror of https://github.com/django/django.git
Fixed #30987 -- Added models.PositiveBigIntegerField.
This commit is contained in:
parent
aa12cf07c9
commit
555bebe774
|
@ -77,6 +77,7 @@ class LayerMapping:
|
|||
models.UUIDField: OFTString,
|
||||
models.BigIntegerField: (OFTInteger, OFTReal, OFTString),
|
||||
models.SmallIntegerField: (OFTInteger, OFTReal, OFTString),
|
||||
models.PositiveBigIntegerField: (OFTInteger, OFTReal, OFTString),
|
||||
models.PositiveIntegerField: (OFTInteger, OFTReal, OFTString),
|
||||
models.PositiveSmallIntegerField: (OFTInteger, OFTReal, OFTString),
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ class BaseDatabaseOperations:
|
|||
'SmallIntegerField': (-32768, 32767),
|
||||
'IntegerField': (-2147483648, 2147483647),
|
||||
'BigIntegerField': (-9223372036854775808, 9223372036854775807),
|
||||
'PositiveBigIntegerField': (0, 9223372036854775807),
|
||||
'PositiveSmallIntegerField': (0, 32767),
|
||||
'PositiveIntegerField': (0, 2147483647),
|
||||
'SmallAutoField': (-32768, 32767),
|
||||
|
|
|
@ -120,6 +120,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
'GenericIPAddressField': 'char(39)',
|
||||
'NullBooleanField': 'bool',
|
||||
'OneToOneField': 'integer',
|
||||
'PositiveBigIntegerField': 'bigint UNSIGNED',
|
||||
'PositiveIntegerField': 'integer UNSIGNED',
|
||||
'PositiveSmallIntegerField': 'smallint UNSIGNED',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
|
@ -339,6 +340,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
def data_type_check_constraints(self):
|
||||
if self.features.supports_column_check_constraints:
|
||||
return {
|
||||
'PositiveBigIntegerField': '`%(column)s` >= 0',
|
||||
'PositiveIntegerField': '`%(column)s` >= 0',
|
||||
'PositiveSmallIntegerField': '`%(column)s` >= 0',
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
|||
elif field_type == 'SmallIntegerField':
|
||||
return 'SmallAutoField'
|
||||
if description.is_unsigned:
|
||||
if field_type == 'IntegerField':
|
||||
if field_type == 'BigIntegerField':
|
||||
return 'PositiveBigIntegerField'
|
||||
elif field_type == 'IntegerField':
|
||||
return 'PositiveIntegerField'
|
||||
elif field_type == 'SmallIntegerField':
|
||||
return 'PositiveSmallIntegerField'
|
||||
|
|
|
@ -15,6 +15,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||
**BaseDatabaseOperations.integer_field_ranges,
|
||||
'PositiveSmallIntegerField': (0, 65535),
|
||||
'PositiveIntegerField': (0, 4294967295),
|
||||
'PositiveBigIntegerField': (0, 18446744073709551615),
|
||||
}
|
||||
cast_data_types = {
|
||||
'AutoField': 'signed integer',
|
||||
|
@ -26,6 +27,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||
'IntegerField': 'signed integer',
|
||||
'BigIntegerField': 'signed integer',
|
||||
'SmallIntegerField': 'signed integer',
|
||||
'PositiveBigIntegerField': 'unsigned integer',
|
||||
'PositiveIntegerField': 'unsigned integer',
|
||||
'PositiveSmallIntegerField': 'unsigned integer',
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
'GenericIPAddressField': 'VARCHAR2(39)',
|
||||
'NullBooleanField': 'NUMBER(1)',
|
||||
'OneToOneField': 'NUMBER(11)',
|
||||
'PositiveBigIntegerField': 'NUMBER(19)',
|
||||
'PositiveIntegerField': 'NUMBER(11)',
|
||||
'PositiveSmallIntegerField': 'NUMBER(11)',
|
||||
'SlugField': 'NVARCHAR2(%(max_length)s)',
|
||||
|
@ -133,6 +134,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
data_type_check_constraints = {
|
||||
'BooleanField': '%(qn_column)s IN (0,1)',
|
||||
'NullBooleanField': '%(qn_column)s IN (0,1)',
|
||||
'PositiveBigIntegerField': '%(qn_column)s >= 0',
|
||||
'PositiveIntegerField': '%(qn_column)s >= 0',
|
||||
'PositiveSmallIntegerField': '%(qn_column)s >= 0',
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||
'SmallIntegerField': (-99999999999, 99999999999),
|
||||
'IntegerField': (-99999999999, 99999999999),
|
||||
'BigIntegerField': (-9999999999999999999, 9999999999999999999),
|
||||
'PositiveBigIntegerField': (0, 9999999999999999999),
|
||||
'PositiveSmallIntegerField': (0, 99999999999),
|
||||
'PositiveIntegerField': (0, 99999999999),
|
||||
'SmallAutoField': (-99999, 99999),
|
||||
|
|
|
@ -16,6 +16,7 @@ class InsertVar:
|
|||
'IntegerField': int,
|
||||
'BigIntegerField': int,
|
||||
'SmallIntegerField': int,
|
||||
'PositiveBigIntegerField': int,
|
||||
'PositiveSmallIntegerField': int,
|
||||
'PositiveIntegerField': int,
|
||||
'FloatField': Database.NATIVE_FLOAT,
|
||||
|
@ -71,6 +72,7 @@ class BulkInsertMapper:
|
|||
'FloatField': NUMBER,
|
||||
'IntegerField': NUMBER,
|
||||
'NullBooleanField': NUMBER,
|
||||
'PositiveBigIntegerField': NUMBER,
|
||||
'PositiveIntegerField': NUMBER,
|
||||
'PositiveSmallIntegerField': NUMBER,
|
||||
'SmallIntegerField': NUMBER,
|
||||
|
|
|
@ -89,6 +89,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
'GenericIPAddressField': 'inet',
|
||||
'NullBooleanField': 'boolean',
|
||||
'OneToOneField': 'integer',
|
||||
'PositiveBigIntegerField': 'bigint',
|
||||
'PositiveIntegerField': 'integer',
|
||||
'PositiveSmallIntegerField': 'smallint',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
|
@ -99,6 +100,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
'UUIDField': 'uuid',
|
||||
}
|
||||
data_type_check_constraints = {
|
||||
'PositiveBigIntegerField': '"%(column)s" >= 0',
|
||||
'PositiveIntegerField': '"%(column)s" >= 0',
|
||||
'PositiveSmallIntegerField': '"%(column)s" >= 0',
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
'GenericIPAddressField': 'char(39)',
|
||||
'NullBooleanField': 'bool',
|
||||
'OneToOneField': 'integer',
|
||||
'PositiveBigIntegerField': 'bigint unsigned',
|
||||
'PositiveIntegerField': 'integer unsigned',
|
||||
'PositiveSmallIntegerField': 'smallint unsigned',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
|
@ -112,6 +113,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
'UUIDField': 'char(32)',
|
||||
}
|
||||
data_type_check_constraints = {
|
||||
'PositiveBigIntegerField': '"%(column)s" >= 0',
|
||||
'PositiveIntegerField': '"%(column)s" >= 0',
|
||||
'PositiveSmallIntegerField': '"%(column)s" >= 0',
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class FlexibleFieldLookupDict:
|
|||
'integer': 'IntegerField',
|
||||
'bigint': 'BigIntegerField',
|
||||
'integer unsigned': 'PositiveIntegerField',
|
||||
'bigint unsigned': 'PositiveBigIntegerField',
|
||||
'decimal': 'DecimalField',
|
||||
'real': 'FloatField',
|
||||
'text': 'TextField',
|
||||
|
|
|
@ -33,9 +33,9 @@ __all__ = [
|
|||
'DateField', 'DateTimeField', 'DecimalField', 'DurationField',
|
||||
'EmailField', 'Empty', 'Field', 'FilePathField', 'FloatField',
|
||||
'GenericIPAddressField', 'IPAddressField', 'IntegerField', 'NOT_PROVIDED',
|
||||
'NullBooleanField', 'PositiveIntegerField', 'PositiveSmallIntegerField',
|
||||
'SlugField', 'SmallAutoField', 'SmallIntegerField', 'TextField',
|
||||
'TimeField', 'URLField', 'UUIDField',
|
||||
'NullBooleanField', 'PositiveBigIntegerField', 'PositiveIntegerField',
|
||||
'PositiveSmallIntegerField', 'SlugField', 'SmallAutoField',
|
||||
'SmallIntegerField', 'TextField', 'TimeField', 'URLField', 'UUIDField',
|
||||
]
|
||||
|
||||
|
||||
|
@ -1955,6 +1955,19 @@ class PositiveIntegerRelDbTypeMixin:
|
|||
return IntegerField().db_type(connection=connection)
|
||||
|
||||
|
||||
class PositiveBigIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField):
|
||||
description = _('Positive big integer')
|
||||
|
||||
def get_internal_type(self):
|
||||
return 'PositiveBigIntegerField'
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
return super().formfield(**{
|
||||
'min_value': 0,
|
||||
**kwargs,
|
||||
})
|
||||
|
||||
|
||||
class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField):
|
||||
description = _("Positive integer")
|
||||
|
||||
|
|
|
@ -1177,6 +1177,17 @@ values are stored as null.
|
|||
Like :class:`BooleanField` with ``null=True``. Use that instead of this field
|
||||
as it's likely to be deprecated in a future version of Django.
|
||||
|
||||
``PositiveBigIntegerField``
|
||||
---------------------------
|
||||
|
||||
.. class:: PositiveBigIntegerField(**options)
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
Like a :class:`PositiveIntegerField`, but only allows values under a certain
|
||||
(database-dependent) point. Values from ``0`` to ``9223372036854775807`` are
|
||||
safe in all databases supported by Django.
|
||||
|
||||
``PositiveIntegerField``
|
||||
------------------------
|
||||
|
||||
|
|
|
@ -194,6 +194,11 @@ Models
|
|||
* ``TREE`` format on MySQL 8.0.16+,
|
||||
* ``analyze`` option on MySQL 8.0.18+ and MariaDB.
|
||||
|
||||
* Added :class:`~django.db.models.PositiveBigIntegerField` which acts much like
|
||||
a :class:`~django.db.models.PositiveIntegerField` except that it only allows
|
||||
values under a certain (database-dependent) limit. Values from ``0`` to
|
||||
``9223372036854775807`` are safe in all databases supported by Django.
|
||||
|
||||
Pagination
|
||||
~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@ Model field Form field
|
|||
|
||||
:class:`NullBooleanField` :class:`~django.forms.NullBooleanField`
|
||||
|
||||
:class:`PositiveBigIntegerField` :class:`~django.forms.IntegerField`
|
||||
|
||||
:class:`PositiveIntegerField` :class:`~django.forms.IntegerField`
|
||||
|
||||
:class:`PositiveSmallIntegerField` :class:`~django.forms.IntegerField`
|
||||
|
|
|
@ -76,6 +76,7 @@ class NullableFields(models.Model):
|
|||
integer_field = models.IntegerField(null=True, default=2)
|
||||
null_boolean_field = models.BooleanField(null=True, default=False)
|
||||
null_boolean_field_old = models.NullBooleanField(null=True, default=False)
|
||||
positive_big_integer_field = models.PositiveBigIntegerField(null=True, default=2 ** 63 - 1)
|
||||
positive_integer_field = models.PositiveIntegerField(null=True, default=3)
|
||||
positive_small_integer_field = models.PositiveSmallIntegerField(null=True, default=4)
|
||||
small_integer_field = models.SmallIntegerField(null=True, default=5)
|
||||
|
|
|
@ -59,6 +59,7 @@ class CastTests(TestCase):
|
|||
models.IntegerField,
|
||||
models.BigIntegerField,
|
||||
models.SmallIntegerField,
|
||||
models.PositiveBigIntegerField,
|
||||
models.PositiveIntegerField,
|
||||
models.PositiveSmallIntegerField,
|
||||
):
|
||||
|
|
|
@ -29,6 +29,7 @@ class CaseTestModel(models.Model):
|
|||
null_boolean_old = models.NullBooleanField()
|
||||
positive_integer = models.PositiveIntegerField(null=True)
|
||||
positive_small_integer = models.PositiveSmallIntegerField(null=True)
|
||||
positive_big_integer = models.PositiveSmallIntegerField(null=True)
|
||||
slug = models.SlugField(default='')
|
||||
small_integer = models.SmallIntegerField(null=True)
|
||||
text = models.TextField(default='')
|
||||
|
|
|
@ -833,6 +833,19 @@ class CaseExpressionTests(TestCase):
|
|||
transform=attrgetter('integer', 'null_boolean_old')
|
||||
)
|
||||
|
||||
def test_update_positive_big_integer(self):
|
||||
CaseTestModel.objects.update(
|
||||
positive_big_integer=Case(
|
||||
When(integer=1, then=1),
|
||||
When(integer=2, then=2),
|
||||
),
|
||||
)
|
||||
self.assertQuerysetEqual(
|
||||
CaseTestModel.objects.all().order_by('pk'),
|
||||
[(1, 1), (2, 2), (3, None), (2, 2), (3, None), (3, None), (4, None)],
|
||||
transform=attrgetter('integer', 'positive_big_integer')
|
||||
)
|
||||
|
||||
def test_update_positive_integer(self):
|
||||
CaseTestModel.objects.update(
|
||||
positive_integer=Case(
|
||||
|
|
|
@ -453,6 +453,13 @@ class FieldDeconstructionTests(SimpleTestCase):
|
|||
self.assertEqual(args, [])
|
||||
self.assertEqual(kwargs, {})
|
||||
|
||||
def test_positive_big_integer_field(self):
|
||||
field = models.PositiveBigIntegerField()
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
self.assertEqual(path, 'django.db.models.PositiveBigIntegerField')
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(kwargs, {})
|
||||
|
||||
def test_slug_field(self):
|
||||
field = models.SlugField()
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
|
|
|
@ -57,6 +57,7 @@ class ColumnTypes(models.Model):
|
|||
float_field = models.FloatField()
|
||||
int_field = models.IntegerField()
|
||||
gen_ip_address_field = models.GenericIPAddressField(protocol="ipv4")
|
||||
pos_big_int_field = models.PositiveBigIntegerField()
|
||||
pos_int_field = models.PositiveIntegerField()
|
||||
pos_small_int_field = models.PositiveSmallIntegerField()
|
||||
slug_field = models.SlugField()
|
||||
|
|
|
@ -118,11 +118,19 @@ class InspectDBTestCase(TestCase):
|
|||
assertFieldType('pos_int_field', "models.IntegerField()")
|
||||
|
||||
if connection.features.can_introspect_positive_integer_field:
|
||||
if connection.features.can_introspect_big_integer_field:
|
||||
assertFieldType('pos_big_int_field', 'models.PositiveBigIntegerField()')
|
||||
else:
|
||||
assertFieldType('pos_big_int_field', 'models.PositiveIntegerField()')
|
||||
if connection.features.can_introspect_small_integer_field:
|
||||
assertFieldType('pos_small_int_field', "models.PositiveSmallIntegerField()")
|
||||
else:
|
||||
assertFieldType('pos_small_int_field', "models.PositiveIntegerField()")
|
||||
else:
|
||||
if connection.features.can_introspect_big_integer_field:
|
||||
assertFieldType('pos_big_int_field', 'models.BigIntegerField()')
|
||||
else:
|
||||
assertFieldType('pos_big_int_field', 'models.IntegerField()')
|
||||
if connection.features.can_introspect_small_integer_field:
|
||||
assertFieldType('pos_small_int_field', "models.SmallIntegerField()")
|
||||
else:
|
||||
|
|
|
@ -689,6 +689,7 @@ class IntegerFieldTests(SimpleTestCase):
|
|||
biginteger = models.BigIntegerField(max_length=2)
|
||||
smallinteger = models.SmallIntegerField(max_length=2)
|
||||
positiveinteger = models.PositiveIntegerField(max_length=2)
|
||||
positivebiginteger = models.PositiveBigIntegerField(max_length=2)
|
||||
positivesmallinteger = models.PositiveSmallIntegerField(max_length=2)
|
||||
|
||||
for field in Model._meta.get_fields():
|
||||
|
|
|
@ -117,6 +117,10 @@ class BigIntegerModel(models.Model):
|
|||
null_value = models.BigIntegerField(null=True, blank=True)
|
||||
|
||||
|
||||
class PositiveBigIntegerModel(models.Model):
|
||||
value = models.PositiveBigIntegerField()
|
||||
|
||||
|
||||
class PositiveSmallIntegerModel(models.Model):
|
||||
value = models.PositiveSmallIntegerField()
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ from django.db import IntegrityError, connection, models
|
|||
from django.test import SimpleTestCase, TestCase
|
||||
|
||||
from .models import (
|
||||
BigIntegerModel, IntegerModel, PositiveIntegerModel,
|
||||
PositiveSmallIntegerModel, SmallIntegerModel,
|
||||
BigIntegerModel, IntegerModel, PositiveBigIntegerModel,
|
||||
PositiveIntegerModel, PositiveSmallIntegerModel, SmallIntegerModel,
|
||||
)
|
||||
|
||||
|
||||
|
@ -182,6 +182,11 @@ class PositiveIntegerFieldTests(IntegerFieldTests):
|
|||
p.save()
|
||||
|
||||
|
||||
class PositiveBigIntegerFieldTests(IntegerFieldTests):
|
||||
model = PositiveBigIntegerModel
|
||||
documented_range = (0, 9223372036854775807)
|
||||
|
||||
|
||||
class ValidationTests(SimpleTestCase):
|
||||
|
||||
class Choices(models.IntegerChoices):
|
||||
|
|
|
@ -4,9 +4,9 @@ from decimal import Decimal
|
|||
from django.db.models.fields import (
|
||||
AutoField, BinaryField, BooleanField, CharField, DateField, DateTimeField,
|
||||
DecimalField, EmailField, FilePathField, FloatField, GenericIPAddressField,
|
||||
IntegerField, IPAddressField, NullBooleanField, PositiveIntegerField,
|
||||
PositiveSmallIntegerField, SlugField, SmallIntegerField, TextField,
|
||||
TimeField, URLField,
|
||||
IntegerField, IPAddressField, NullBooleanField, PositiveBigIntegerField,
|
||||
PositiveIntegerField, PositiveSmallIntegerField, SlugField,
|
||||
SmallIntegerField, TextField, TimeField, URLField,
|
||||
)
|
||||
from django.db.models.fields.files import FileField, ImageField
|
||||
from django.test import SimpleTestCase
|
||||
|
@ -97,6 +97,10 @@ class PromiseTest(SimpleTestCase):
|
|||
lazy_func = lazy(lambda: 1, int)
|
||||
self.assertIsInstance(PositiveSmallIntegerField().get_prep_value(lazy_func()), int)
|
||||
|
||||
def test_PositiveBigIntegerField(self):
|
||||
lazy_func = lazy(lambda: 1, int)
|
||||
self.assertIsInstance(PositiveBigIntegerField().get_prep_value(lazy_func()), int)
|
||||
|
||||
def test_SlugField(self):
|
||||
lazy_func = lazy(lambda: 'slug', str)
|
||||
self.assertIsInstance(SlugField().get_prep_value(lazy_func()), str)
|
||||
|
|
|
@ -72,6 +72,10 @@ class NullBooleanData(models.Model):
|
|||
data = models.NullBooleanField(null=True)
|
||||
|
||||
|
||||
class PositiveBigIntegerData(models.Model):
|
||||
data = models.PositiveBigIntegerField(null=True)
|
||||
|
||||
|
||||
class PositiveIntegerData(models.Model):
|
||||
data = models.PositiveIntegerField(null=True)
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ from .models import (
|
|||
GenericData, GenericIPAddressData, GenericIPAddressPKData,
|
||||
InheritAbstractModel, InheritBaseModel, IntegerData, IntegerPKData,
|
||||
Intermediate, LengthModel, M2MData, M2MIntermediateData, M2MSelfData,
|
||||
ModifyingSaveData, NullBooleanData, O2OData, PositiveIntegerData,
|
||||
PositiveIntegerPKData, PositiveSmallIntegerData,
|
||||
ModifyingSaveData, NullBooleanData, O2OData, PositiveBigIntegerData,
|
||||
PositiveIntegerData, PositiveIntegerPKData, PositiveSmallIntegerData,
|
||||
PositiveSmallIntegerPKData, SlugData, SlugPKData, SmallData, SmallPKData,
|
||||
Tag, TextData, TimeData, UniqueAnchor, UUIDData,
|
||||
)
|
||||
|
@ -241,6 +241,8 @@ test_data = [
|
|||
(data_obj, 100, NullBooleanData, True),
|
||||
(data_obj, 101, NullBooleanData, False),
|
||||
(data_obj, 102, NullBooleanData, None),
|
||||
(data_obj, 110, PositiveBigIntegerData, 9223372036854775807),
|
||||
(data_obj, 111, PositiveBigIntegerData, None),
|
||||
(data_obj, 120, PositiveIntegerData, 123456789),
|
||||
(data_obj, 121, PositiveIntegerData, None),
|
||||
(data_obj, 130, PositiveSmallIntegerData, 12),
|
||||
|
|
Loading…
Reference in New Issue