Fixed #399: Added big integer field. Thanks to Tomáš Kopeček for persistently maintaining a patch for this.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11887 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
fd4cc65baf
commit
5bd63663a9
1
AUTHORS
1
AUTHORS
|
@ -246,6 +246,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Cameron Knight (ckknight)
|
||||
Nena Kojadin <nena@kiberpipa.org>
|
||||
Igor Kolar <ike@email.si>
|
||||
Tomáš Kopeček <permonik@m6.cz>
|
||||
Gasper Koren
|
||||
Martin Kosír <martin@martinkosir.net>
|
||||
Arthur Koziel <http://arthurkoziel.com>
|
||||
|
|
|
@ -42,14 +42,15 @@ FORMFIELD_FOR_DBFIELD_DEFAULTS = {
|
|||
'form_class': forms.SplitDateTimeField,
|
||||
'widget': widgets.AdminSplitDateTime
|
||||
},
|
||||
models.DateField: {'widget': widgets.AdminDateWidget},
|
||||
models.TimeField: {'widget': widgets.AdminTimeWidget},
|
||||
models.TextField: {'widget': widgets.AdminTextareaWidget},
|
||||
models.URLField: {'widget': widgets.AdminURLFieldWidget},
|
||||
models.IntegerField: {'widget': widgets.AdminIntegerFieldWidget},
|
||||
models.CharField: {'widget': widgets.AdminTextInputWidget},
|
||||
models.ImageField: {'widget': widgets.AdminFileWidget},
|
||||
models.FileField: {'widget': widgets.AdminFileWidget},
|
||||
models.DateField: {'widget': widgets.AdminDateWidget},
|
||||
models.TimeField: {'widget': widgets.AdminTimeWidget},
|
||||
models.TextField: {'widget': widgets.AdminTextareaWidget},
|
||||
models.URLField: {'widget': widgets.AdminURLFieldWidget},
|
||||
models.IntegerField: {'widget': widgets.AdminIntegerFieldWidget},
|
||||
models.BigIntegerField: {'widget': widgets.AdminIntegerFieldWidget},
|
||||
models.CharField: {'widget': widgets.AdminTextInputWidget},
|
||||
models.ImageField: {'widget': widgets.AdminFileWidget},
|
||||
models.FileField: {'widget': widgets.AdminFileWidget},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ class DatabaseCreation(BaseDatabaseCreation):
|
|||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'double precision',
|
||||
'IntegerField': 'integer',
|
||||
'BigIntegerField': 'bigint',
|
||||
'IPAddressField': 'char(15)',
|
||||
'NullBooleanField': 'bool',
|
||||
'OneToOneField': 'integer',
|
||||
|
|
|
@ -17,7 +17,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
|||
FIELD_TYPE.FLOAT: 'FloatField',
|
||||
FIELD_TYPE.INT24: 'IntegerField',
|
||||
FIELD_TYPE.LONG: 'IntegerField',
|
||||
FIELD_TYPE.LONGLONG: 'IntegerField',
|
||||
FIELD_TYPE.LONGLONG: 'BigIntegerField',
|
||||
FIELD_TYPE.SHORT: 'IntegerField',
|
||||
FIELD_TYPE.STRING: 'CharField',
|
||||
FIELD_TYPE.TIMESTAMP: 'DateTimeField',
|
||||
|
|
|
@ -27,6 +27,7 @@ class DatabaseCreation(BaseDatabaseCreation):
|
|||
'FilePathField': 'NVARCHAR2(%(max_length)s)',
|
||||
'FloatField': 'DOUBLE PRECISION',
|
||||
'IntegerField': 'NUMBER(11)',
|
||||
'BigIntegerField': 'NUMBER(19)',
|
||||
'IPAddressField': 'VARCHAR2(15)',
|
||||
'NullBooleanField': 'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))',
|
||||
'OneToOneField': 'NUMBER(11)',
|
||||
|
|
|
@ -29,7 +29,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
|||
def get_field_type(self, data_type, description):
|
||||
# If it's a NUMBER with scale == 0, consider it an IntegerField
|
||||
if data_type == cx_Oracle.NUMBER and description[5] == 0:
|
||||
return 'IntegerField'
|
||||
if description[4] > 11:
|
||||
return 'BigIntegerField'
|
||||
else:
|
||||
return 'IntegerField'
|
||||
else:
|
||||
return super(DatabaseIntrospection, self).get_field_type(
|
||||
data_type, description)
|
||||
|
|
|
@ -18,6 +18,7 @@ class DatabaseCreation(BaseDatabaseCreation):
|
|||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'double precision',
|
||||
'IntegerField': 'integer',
|
||||
'BigIntegerField': 'bigint',
|
||||
'IPAddressField': 'inet',
|
||||
'NullBooleanField': 'boolean',
|
||||
'OneToOneField': 'integer',
|
||||
|
|
|
@ -4,6 +4,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
|||
# Maps type codes to Django Field types.
|
||||
data_types_reverse = {
|
||||
16: 'BooleanField',
|
||||
20: 'BigIntegerField',
|
||||
21: 'SmallIntegerField',
|
||||
23: 'IntegerField',
|
||||
25: 'TextField',
|
||||
|
|
|
@ -19,6 +19,7 @@ class DatabaseCreation(BaseDatabaseCreation):
|
|||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'real',
|
||||
'IntegerField': 'integer',
|
||||
'BigIntegerField': 'bigint',
|
||||
'IPAddressField': 'char(15)',
|
||||
'NullBooleanField': 'bool',
|
||||
'OneToOneField': 'integer',
|
||||
|
|
|
@ -16,6 +16,7 @@ class FlexibleFieldLookupDict:
|
|||
'smallinteger': 'SmallIntegerField',
|
||||
'int': 'IntegerField',
|
||||
'integer': 'IntegerField',
|
||||
'bigint': 'BigIntegerField',
|
||||
'integer unsigned': 'PositiveIntegerField',
|
||||
'decimal': 'DecimalField',
|
||||
'real': 'FloatField',
|
||||
|
|
|
@ -732,6 +732,19 @@ class IntegerField(Field):
|
|||
defaults.update(kwargs)
|
||||
return super(IntegerField, self).formfield(**defaults)
|
||||
|
||||
class BigIntegerField(IntegerField):
|
||||
empty_strings_allowed = False
|
||||
description = ugettext_lazy("Big (8 byte) integer")
|
||||
MAX_BIGINT = 9223372036854775807
|
||||
def get_internal_type(self):
|
||||
return "BigIntegerField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'min_value': -BigIntegerField.MAX_BIGINT - 1,
|
||||
'max_value': BigIntegerField.MAX_BIGINT}
|
||||
defaults.update(kwargs)
|
||||
return super(BigIntegerField, self).formfield(**defaults)
|
||||
|
||||
class IPAddressField(Field):
|
||||
empty_strings_allowed = False
|
||||
description = ugettext_lazy("IP address")
|
||||
|
|
|
@ -299,6 +299,18 @@ according to available IDs. You usually won't need to use this directly; a
|
|||
primary key field will automatically be added to your model if you don't specify
|
||||
otherwise. See :ref:`automatic-primary-key-fields`.
|
||||
|
||||
``BigIntegerField``
|
||||
-------------------
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
.. class:: BigIntegerField([**options])
|
||||
|
||||
A 64 bit integer, much like an :class:`IntegerField` except that it is
|
||||
guaranteed to fit numbers from -9223372036854775808 to 9223372036854775807. The
|
||||
admin represents this as an ``<input type="text">`` (a single-line input).
|
||||
|
||||
|
||||
``BooleanField``
|
||||
----------------
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ the full list of conversions:
|
|||
=============================== ========================================
|
||||
``AutoField`` Not represented in the form
|
||||
|
||||
``BigIntegerField`` ``IntegerField`` with ``min_value`` set
|
||||
to -9223372036854775808 and ``max_value``
|
||||
set to 9223372036854775807.
|
||||
|
||||
``BooleanField`` ``BooleanField``
|
||||
|
||||
``CharField`` ``CharField`` with ``max_length`` set to
|
||||
|
@ -108,6 +112,10 @@ the full list of conversions:
|
|||
The ``FloatField`` form field and ``DecimalField`` model and form fields
|
||||
are new in Django 1.0.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
The ``BigIntegerField`` is new in Django 1.2.
|
||||
|
||||
|
||||
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
|
||||
types are special cases:
|
||||
|
||||
|
|
|
@ -13,12 +13,6 @@ import tempfile
|
|||
from django.db import models
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
|
||||
# Python 2.3 doesn't have sorted()
|
||||
try:
|
||||
sorted
|
||||
except NameError:
|
||||
from django.utils.itercompat import sorted
|
||||
|
||||
temp_storage_dir = tempfile.mkdtemp()
|
||||
temp_storage = FileSystemStorage(temp_storage_dir)
|
||||
|
||||
|
@ -201,6 +195,12 @@ class Post(models.Model):
|
|||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class BigInt(models.Model):
|
||||
biggie = models.BigIntegerField()
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.biggie)
|
||||
|
||||
__test__ = {'API_TESTS': """
|
||||
>>> from django import forms
|
||||
>>> from django.forms.models import ModelForm, model_to_dict
|
||||
|
@ -1145,6 +1145,28 @@ True
|
|||
# Delete the current file since this is not done by Django.
|
||||
>>> instance.file.delete()
|
||||
>>> instance.delete()
|
||||
|
||||
# BigIntegerField ################################################################
|
||||
>>> class BigIntForm(forms.ModelForm):
|
||||
... class Meta:
|
||||
... model = BigInt
|
||||
...
|
||||
>>> bif = BigIntForm({'biggie': '-9223372036854775808'})
|
||||
>>> bif.is_valid()
|
||||
True
|
||||
>>> bif = BigIntForm({'biggie': '-9223372036854775809'})
|
||||
>>> bif.is_valid()
|
||||
False
|
||||
>>> bif.errors
|
||||
{'biggie': [u'Ensure this value is greater than or equal to -9223372036854775808.']}
|
||||
>>> bif = BigIntForm({'biggie': '9223372036854775807'})
|
||||
>>> bif.is_valid()
|
||||
True
|
||||
>>> bif = BigIntForm({'biggie': '9223372036854775808'})
|
||||
>>> bif.is_valid()
|
||||
False
|
||||
>>> bif.errors
|
||||
{'biggie': [u'Ensure this value is less than or equal to 9223372036854775807.']}
|
||||
"""}
|
||||
|
||||
if test_images:
|
||||
|
|
|
@ -4,6 +4,7 @@ class Reporter(models.Model):
|
|||
first_name = models.CharField(max_length=30)
|
||||
last_name = models.CharField(max_length=30)
|
||||
email = models.EmailField()
|
||||
facebook_user_id = models.BigIntegerField()
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s" % (self.first_name, self.last_name)
|
||||
|
|
|
@ -77,7 +77,7 @@ class IntrospectionTests(TestCase):
|
|||
cursor = connection.cursor()
|
||||
desc = connection.introspection.get_table_description(cursor, Reporter._meta.db_table)
|
||||
self.assertEqual([datatype(r[1], r) for r in desc],
|
||||
['IntegerField', 'CharField', 'CharField', 'CharField'])
|
||||
['IntegerField', 'CharField', 'CharField', 'CharField', 'BigIntegerField'])
|
||||
|
||||
# Regression test for #9991 - 'real' types in postgres
|
||||
if settings.DATABASE_ENGINE.startswith('postgresql'):
|
||||
|
|
|
@ -51,6 +51,9 @@ class BigD(models.Model):
|
|||
class BigS(models.Model):
|
||||
s = models.SlugField(max_length=255)
|
||||
|
||||
class BigInt(models.Model):
|
||||
value = models.BigIntegerField()
|
||||
null_value = models.BigIntegerField(null = True, blank = True)
|
||||
|
||||
###############################################################################
|
||||
# ImageField
|
||||
|
|
|
@ -6,7 +6,7 @@ from django import forms
|
|||
from django.db import models
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from models import Foo, Bar, Whiz, BigD, BigS, Image
|
||||
from models import Foo, Bar, Whiz, BigD, BigS, Image, BigInt
|
||||
|
||||
try:
|
||||
from decimal import Decimal
|
||||
|
@ -144,3 +144,32 @@ class SlugFieldTests(django.test.TestCase):
|
|||
bs = BigS.objects.create(s = 'slug'*50)
|
||||
bs = BigS.objects.get(pk=bs.pk)
|
||||
self.assertEqual(bs.s, 'slug'*50)
|
||||
|
||||
class BigIntegerFieldTests(django.test.TestCase):
|
||||
def test_limits(self):
|
||||
# Ensure that values that are right at the limits can be saved
|
||||
# and then retrieved without corruption.
|
||||
maxval = 9223372036854775807
|
||||
minval = -maxval - 1
|
||||
BigInt.objects.create(value=maxval)
|
||||
qs = BigInt.objects.filter(value__gte=maxval)
|
||||
self.assertEqual(qs.count(), 1)
|
||||
self.assertEqual(qs[0].value, maxval)
|
||||
BigInt.objects.create(value=minval)
|
||||
qs = BigInt.objects.filter(value__lte=minval)
|
||||
self.assertEqual(qs.count(), 1)
|
||||
self.assertEqual(qs[0].value, minval)
|
||||
|
||||
def test_types(self):
|
||||
b = BigInt(value = 0)
|
||||
self.assertTrue(isinstance(b.value, (int, long)))
|
||||
b.save()
|
||||
self.assertTrue(isinstance(b.value, (int, long)))
|
||||
b = BigInt.objects.all()[0]
|
||||
self.assertTrue(isinstance(b.value, (int, long)))
|
||||
|
||||
def test_coercing(self):
|
||||
BigInt.objects.create(value ='10')
|
||||
b = BigInt.objects.get(value = '10')
|
||||
self.assertEqual(b.value, 10)
|
||||
|
||||
|
|
|
@ -43,6 +43,9 @@ class FloatData(models.Model):
|
|||
class IntegerData(models.Model):
|
||||
data = models.IntegerField(null=True)
|
||||
|
||||
class BigIntegerData(models.Model):
|
||||
data = models.BigIntegerField(null=True)
|
||||
|
||||
# class ImageData(models.Model):
|
||||
# data = models.ImageField(null=True)
|
||||
|
||||
|
|
|
@ -321,6 +321,11 @@ The end."""),
|
|||
(inherited_obj, 900, InheritAbstractModel, {'child_data':37,'parent_data':42}),
|
||||
(inherited_obj, 910, ExplicitInheritBaseModel, {'child_data':37,'parent_data':42}),
|
||||
(inherited_obj, 920, InheritBaseModel, {'child_data':37,'parent_data':42}),
|
||||
|
||||
(data_obj, 1000, BigIntegerData, 9223372036854775807),
|
||||
(data_obj, 1001, BigIntegerData, -9223372036854775808),
|
||||
(data_obj, 1002, BigIntegerData, 0),
|
||||
(data_obj, 1003, BigIntegerData, None),
|
||||
]
|
||||
|
||||
# Because Oracle treats the empty string as NULL, Oracle is expected to fail
|
||||
|
|
Loading…
Reference in New Issue