1
0
mirror of https://github.com/django/django.git synced 2025-07-04 01:39:20 +00:00

[soc2009/multidb] Merged up to trunk r11900.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11902 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2009-12-17 22:07:42 +00:00
parent d255be2619
commit 2269813616
23 changed files with 202 additions and 87 deletions

View File

@ -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>

View File

@ -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},
}

View File

@ -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

View File

@ -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))

View File

@ -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',

View File

@ -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',

View File

@ -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)',

View File

@ -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)

View File

@ -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',

View File

@ -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',

View File

@ -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',

View File

@ -16,6 +16,7 @@ class FlexibleFieldLookupDict:
'smallinteger': 'SmallIntegerField',
'int': 'IntegerField',
'integer': 'IntegerField',
'bigint': 'BigIntegerField',
'integer unsigned': 'PositiveIntegerField',
'decimal': 'DecimalField',
'real': 'FloatField',

View File

@ -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")

View File

@ -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``
----------------

View File

@ -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:

View File

@ -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:

View File

@ -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 (<type 'float'>)
[{"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 (<type 'float'>)
>>> 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 (<type 'float'>)
# 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.

View File

@ -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)

View File

@ -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'):

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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