diff --git a/AUTHORS b/AUTHORS index bf7ee55533..c8d91f77c7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -246,6 +246,7 @@ answer newbie questions, and generally made Django that much better: Cameron Knight (ckknight) Nena Kojadin Igor Kolar + Tomáš Kopeček Gasper Koren Martin Kosír Arthur Koziel diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index be0fcc10f0..8fa0fbbf01 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -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}, } diff --git a/django/contrib/gis/measure.py b/django/contrib/gis/measure.py index 37922040df..a60398bccd 100644 --- a/django/contrib/gis/measure.py +++ b/django/contrib/gis/measure.py @@ -27,7 +27,7 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # """ -Distance and Area objects to allow for sensible and convienient calculation +Distance and Area objects to allow for sensible and convienient calculation and conversions. Authors: Robert Coup, Justin Bronn @@ -70,7 +70,7 @@ class MeasureBase(object): @classmethod def unit_attname(cls, unit_str): """ - Retrieves the unit attribute name for the given unit string. + Retrieves the unit attribute name for the given unit string. For example, if the given unit string is 'metre', 'm' would be returned. An exception is raised if an attribute cannot be found. """ @@ -165,51 +165,51 @@ class Distance(MeasureBase): self.m, self._default_unit = self.default_units(kwargs) if default_unit and isinstance(default_unit, str): self._default_unit = default_unit - + def __getattr__(self, name): if name in self.UNITS: return self.m / self.UNITS[name] else: raise AttributeError('Unknown unit type: %s' % name) - + def __repr__(self): return 'Distance(%s=%s)' % (self._default_unit, getattr(self, self._default_unit)) def __str__(self): return '%s %s' % (getattr(self, self._default_unit), self._default_unit) - + def __cmp__(self, other): if isinstance(other, Distance): return cmp(self.m, other.m) else: return NotImplemented - + def __add__(self, other): if isinstance(other, Distance): return Distance(default_unit=self._default_unit, m=(self.m + other.m)) else: raise TypeError('Distance must be added with Distance') - + def __iadd__(self, other): if isinstance(other, Distance): self.m += other.m return self else: raise TypeError('Distance must be added with Distance') - + def __sub__(self, other): if isinstance(other, Distance): return Distance(default_unit=self._default_unit, m=(self.m - other.m)) else: raise TypeError('Distance must be subtracted from Distance') - + def __isub__(self, other): if isinstance(other, Distance): self.m -= other.m return self else: raise TypeError('Distance must be subtracted from Distance') - + def __mul__(self, other): if isinstance(other, (int, float, long, Decimal)): return Distance(default_unit=self._default_unit, m=(self.m * float(other))) @@ -217,14 +217,17 @@ class Distance(MeasureBase): return Area(default_unit='sq_' + self._default_unit, sq_m=(self.m * other.m)) else: raise TypeError('Distance must be multiplied with number or Distance') - + def __imul__(self, other): if isinstance(other, (int, float, long, Decimal)): self.m *= float(other) return self else: raise TypeError('Distance must be multiplied with number') - + + def __rmul__(self, other): + return self * other + def __div__(self, other): if isinstance(other, (int, float, long, Decimal)): return Distance(default_unit=self._default_unit, m=(self.m / float(other))) @@ -251,13 +254,13 @@ class Area(MeasureBase): self.sq_m, self._default_unit = self.default_units(kwargs) if default_unit and isinstance(default_unit, str): self._default_unit = default_unit - + def __getattr__(self, name): if name in self.UNITS: return self.sq_m / self.UNITS[name] else: raise AttributeError('Unknown unit type: ' + name) - + def __repr__(self): return 'Area(%s=%s)' % (self._default_unit, getattr(self, self._default_unit)) @@ -269,46 +272,49 @@ class Area(MeasureBase): return cmp(self.sq_m, other.sq_m) else: return NotImplemented - + def __add__(self, other): if isinstance(other, Area): return Area(default_unit=self._default_unit, sq_m=(self.sq_m + other.sq_m)) else: raise TypeError('Area must be added with Area') - + def __iadd__(self, other): if isinstance(other, Area): self.sq_m += other.sq_m return self else: raise TypeError('Area must be added with Area') - + def __sub__(self, other): if isinstance(other, Area): return Area(default_unit=self._default_unit, sq_m=(self.sq_m - other.sq_m)) else: raise TypeError('Area must be subtracted from Area') - + def __isub__(self, other): if isinstance(other, Area): self.sq_m -= other.sq_m return self else: raise TypeError('Area must be subtracted from Area') - + def __mul__(self, other): if isinstance(other, (int, float, long, Decimal)): return Area(default_unit=self._default_unit, sq_m=(self.sq_m * float(other))) else: raise TypeError('Area must be multiplied with number') - + def __imul__(self, other): if isinstance(other, (int, float, long, Decimal)): self.sq_m *= float(other) return self else: raise TypeError('Area must be multiplied with number') - + + def __rmul__(self, other): + return self * other + def __div__(self, other): if isinstance(other, (int, float, long, Decimal)): return Area(default_unit=self._default_unit, sq_m=(self.sq_m / float(other))) @@ -324,7 +330,7 @@ class Area(MeasureBase): def __nonzero__(self): return bool(self.sq_m) - + # Shortcuts D = Distance A = Area diff --git a/django/contrib/gis/tests/test_measure.py b/django/contrib/gis/tests/test_measure.py index 43bc8ae691..28d50488ff 100644 --- a/django/contrib/gis/tests/test_measure.py +++ b/django/contrib/gis/tests/test_measure.py @@ -95,6 +95,8 @@ class DistanceTest(unittest.TestCase): d3 = d1 * 2 self.assertEqual(d3.m, 200) + d3 = 2 * d1 + self.assertEqual(d3.m, 200) d3 *= 5 self.assertEqual(d3.m, 1000) @@ -248,6 +250,8 @@ class AreaTest(unittest.TestCase): a3 = a1 * 2 self.assertEqual(a3.sq_m, 200) + a3 = 2 * a1 + self.assertEqual(a3.sq_m, 200) a3 *= 5 self.assertEqual(a3.sq_m, 1000) @@ -319,7 +323,6 @@ class AreaTest(unittest.TestCase): self.assertEqual(repr(a1), 'Area(sq_m=100.0)') self.assertEqual(repr(a2), 'Area(sq_km=3.5)') - def suite(): s = unittest.TestSuite() s.addTest(unittest.makeSuite(DistanceTest)) diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py index f6243d5d91..8b026a908d 100644 --- a/django/db/backends/mysql/creation.py +++ b/django/db/backends/mysql/creation.py @@ -17,6 +17,7 @@ class DatabaseCreation(BaseDatabaseCreation): 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', + 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py index d8d59b73a1..9e1518b06e 100644 --- a/django/db/backends/mysql/introspection.py +++ b/django/db/backends/mysql/introspection.py @@ -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', diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index 1b13f7b27c..e6e242b9f7 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -26,6 +26,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)', diff --git a/django/db/backends/oracle/introspection.py b/django/db/backends/oracle/introspection.py index 0b4f61a360..0dd0304302 100644 --- a/django/db/backends/oracle/introspection.py +++ b/django/db/backends/oracle/introspection.py @@ -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) diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py index fe1b9023b5..2d509dabe3 100644 --- a/django/db/backends/postgresql/creation.py +++ b/django/db/backends/postgresql/creation.py @@ -17,6 +17,7 @@ class DatabaseCreation(BaseDatabaseCreation): 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', + 'BigIntegerField': 'bigint', 'IPAddressField': 'inet', 'NullBooleanField': 'boolean', 'OneToOneField': 'integer', diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py index a6cafcd949..534bf41d46 100644 --- a/django/db/backends/postgresql/introspection.py +++ b/django/db/backends/postgresql/introspection.py @@ -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', diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py index fc4040103c..03897078a2 100644 --- a/django/db/backends/sqlite3/creation.py +++ b/django/db/backends/sqlite3/creation.py @@ -18,6 +18,7 @@ class DatabaseCreation(BaseDatabaseCreation): 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'real', 'IntegerField': 'integer', + 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py index b58e6a7faf..ce64908873 100644 --- a/django/db/backends/sqlite3/introspection.py +++ b/django/db/backends/sqlite3/introspection.py @@ -16,6 +16,7 @@ class FlexibleFieldLookupDict: 'smallinteger': 'SmallIntegerField', 'int': 'IntegerField', 'integer': 'IntegerField', + 'bigint': 'BigIntegerField', 'integer unsigned': 'PositiveIntegerField', 'decimal': 'DecimalField', 'real': 'FloatField', diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index d8b0c648c8..c86e63a6fc 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -778,6 +778,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") diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 0cb5be4b92..cd8cdc7a01 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -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 ```` (a single-line input). + + ``BooleanField`` ---------------- diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index c5aa9c8a77..024479508a 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -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: diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 0fd24c18ad..c94e6d3e95 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -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: diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py index d34bc3fc0e..632234256f 100644 --- a/tests/regressiontests/fixtures_regress/models.py +++ b/tests/regressiontests/fixtures_regress/models.py @@ -130,6 +130,49 @@ class Book(models.Model): ', '.join(s.name for s in self.stores.all()) ) +# ome models with pathological circular dependencies +class Circle1(models.Model): + name = models.CharField(max_length=255) + def natural_key(self): + return self.name + natural_key.dependencies = ['fixtures_regress.circle2'] + +class Circle2(models.Model): + name = models.CharField(max_length=255) + def natural_key(self): + return self.name + natural_key.dependencies = ['fixtures_regress.circle1'] + +class Circle3(models.Model): + name = models.CharField(max_length=255) + def natural_key(self): + return self.name + natural_key.dependencies = ['fixtures_regress.circle3'] + +class Circle4(models.Model): + name = models.CharField(max_length=255) + def natural_key(self): + return self.name + natural_key.dependencies = ['fixtures_regress.circle5'] + +class Circle5(models.Model): + name = models.CharField(max_length=255) + def natural_key(self): + return self.name + natural_key.dependencies = ['fixtures_regress.circle6'] + +class Circle6(models.Model): + name = models.CharField(max_length=255) + def natural_key(self): + return self.name + natural_key.dependencies = ['fixtures_regress.circle4'] + +class ExternalDependency(models.Model): + name = models.CharField(max_length=255) + def natural_key(self): + return self.name + natural_key.dependencies = ['fixtures_regress.book'] + __test__ = {'API_TESTS':""" >>> from django.core import management @@ -236,8 +279,7 @@ Weight = 1.2 () [{"pk": 1, "model": "fixtures_regress.animal", "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}, {"pk": 2, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.29..., "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}, {"pk": 10, "model": "fixtures_regress.animal", "fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}}] ############################################### -# Regression for #11428 - Proxy models aren't included -# when you run dumpdata over an entire app +# Regression for #11428 - Proxy models aren't included when you dumpdata # Flush out the database first >>> management.call_command('reset', 'fixtures_regress', interactive=False, verbosity=0) @@ -246,7 +288,7 @@ Weight = 1.2 () >>> Widget(name='grommet').save() # Dump data for the entire app. The proxy class shouldn't be included ->>> management.call_command('dumpdata', 'fixtures_regress', format='json') +>>> management.call_command('dumpdata', 'fixtures_regress.widget', 'fixtures_regress.widgetproxy', format='json') [{"pk": 1, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}] ############################################### @@ -259,49 +301,6 @@ Weight = 1.2 () # Now lets check the dependency sorting explicitly -# First Some models with pathological circular dependencies ->>> class Circle1(models.Model): -... name = models.CharField(max_length=255) -... def natural_key(self): -... return self.name -... natural_key.dependencies = ['fixtures_regress.circle2'] - ->>> class Circle2(models.Model): -... name = models.CharField(max_length=255) -... def natural_key(self): -... return self.name -... natural_key.dependencies = ['fixtures_regress.circle1'] - ->>> class Circle3(models.Model): -... name = models.CharField(max_length=255) -... def natural_key(self): -... return self.name -... natural_key.dependencies = ['fixtures_regress.circle3'] - ->>> class Circle4(models.Model): -... name = models.CharField(max_length=255) -... def natural_key(self): -... return self.name -... natural_key.dependencies = ['fixtures_regress.circle5'] - ->>> class Circle5(models.Model): -... name = models.CharField(max_length=255) -... def natural_key(self): -... return self.name -... natural_key.dependencies = ['fixtures_regress.circle6'] - ->>> class Circle6(models.Model): -... name = models.CharField(max_length=255) -... def natural_key(self): -... return self.name -... natural_key.dependencies = ['fixtures_regress.circle4'] - ->>> class ExternalDependency(models.Model): -... name = models.CharField(max_length=255) -... def natural_key(self): -... return self.name -... natural_key.dependencies = ['fixtures_regress.book'] - # It doesn't matter what order you mention the models # Store *must* be serialized before then Person, and both # must be serialized before Book. diff --git a/tests/regressiontests/introspection/models.py b/tests/regressiontests/introspection/models.py index 3227067bd8..ef485e3a3c 100644 --- a/tests/regressiontests/introspection/models.py +++ b/tests/regressiontests/introspection/models.py @@ -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) diff --git a/tests/regressiontests/introspection/tests.py b/tests/regressiontests/introspection/tests.py index e11719e507..10250294c5 100644 --- a/tests/regressiontests/introspection/tests.py +++ b/tests/regressiontests/introspection/tests.py @@ -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.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'].startswith('django.db.backends.postgresql'): diff --git a/tests/regressiontests/model_fields/models.py b/tests/regressiontests/model_fields/models.py index 81e6c22f09..ab841ce409 100644 --- a/tests/regressiontests/model_fields/models.py +++ b/tests/regressiontests/model_fields/models.py @@ -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 diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py index ce18c3cd98..f31193e269 100644 --- a/tests/regressiontests/model_fields/tests.py +++ b/tests/regressiontests/model_fields/tests.py @@ -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 @@ -146,3 +146,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) + diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py index 313ed8fc3a..ccd850326d 100644 --- a/tests/regressiontests/serializers_regress/models.py +++ b/tests/regressiontests/serializers_regress/models.py @@ -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) diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index 8cefb995f9..11b53a5277 100644 --- a/tests/regressiontests/serializers_regress/tests.py +++ b/tests/regressiontests/serializers_regress/tests.py @@ -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