summaryrefslogtreecommitdiff
path: root/django/db/backends
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2009-01-15 11:06:34 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2009-01-15 11:06:34 +0000
commitcc4e4d9aee0b3ebfb45bee01aec79edc9e144c78 (patch)
tree2cdba846a105d406ecceff2c02e071c50502d487 /django/db/backends
parent50a293a0c31e7325ebd520338f9c8881f951d8a7 (diff)
Fixed #3566 -- Added support for aggregation to the ORM. See the documentation for details on usage.
Many thanks to: * Nicolas Lara, who worked on this feature during the 2008 Google Summer of Code. * Alex Gaynor for his help debugging and fixing a number of issues. * Justin Bronn for his help integrating with contrib.gis. * Karen Tracey for her help with cross-platform testing. * Ian Kelly for his help testing and fixing Oracle support. * Malcolm Tredinnick for his invaluable review notes. git-svn-id: http://code.djangoproject.com/svn/django/trunk@9742 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db/backends')
-rw-r--r--django/db/backends/__init__.py23
-rw-r--r--django/db/backends/mysql/base.py1
-rw-r--r--django/db/backends/oracle/query.py20
-rw-r--r--django/db/backends/sqlite3/base.py22
4 files changed, 54 insertions, 12 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 736667d2ff..33ec14e4d7 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -10,6 +10,12 @@ except NameError:
# Python 2.3 compat
from sets import Set as set
+try:
+ import decimal
+except ImportError:
+ # Python 2.3 fallback
+ from django.utils import _decimal as decimal
+
from django.db.backends import util
from django.utils import datetime_safe
@@ -62,6 +68,7 @@ class BaseDatabaseWrapper(local):
return util.CursorDebugWrapper(cursor, self)
class BaseDatabaseFeatures(object):
+ allows_group_by_pk = False
# True if django.db.backend.utils.typecast_timestamp is used on values
# returned from dates() calls.
needs_datetime_string_cast = True
@@ -376,6 +383,22 @@ class BaseDatabaseOperations(object):
"""
return self.year_lookup_bounds(value)
+ def convert_values(self, value, field):
+ """Coerce the value returned by the database backend into a consistent type that
+ is compatible with the field type.
+ """
+ internal_type = field.get_internal_type()
+ if internal_type == 'DecimalField':
+ return value
+ elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
+ return int(value)
+ elif internal_type in ('DateField', 'DateTimeField', 'TimeField'):
+ return value
+ # No field, or the field isn't known to be a decimal or integer
+ # Default to a float
+ return float(value)
+
+
class BaseDatabaseIntrospection(object):
"""
This class encapsulates all backend-specific introspection utilities
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index f6eccb94b7..bb3e129779 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -110,6 +110,7 @@ class CursorWrapper(object):
class DatabaseFeatures(BaseDatabaseFeatures):
empty_fetchmany_value = ()
update_can_self_select = False
+ allows_group_by_pk = True
related_fields_match_type = True
class DatabaseOperations(BaseDatabaseOperations):
diff --git a/django/db/backends/oracle/query.py b/django/db/backends/oracle/query.py
index de169d6901..a86e922b95 100644
--- a/django/db/backends/oracle/query.py
+++ b/django/db/backends/oracle/query.py
@@ -53,21 +53,23 @@ def query_class(QueryClass, Database):
return values
def convert_values(self, value, field):
- from django.db.models.fields import DateField, DateTimeField, \
- TimeField, BooleanField, NullBooleanField, DecimalField, Field
+ from django.db.models.fields import Field
if isinstance(value, Database.LOB):
value = value.read()
# Oracle stores empty strings as null. We need to undo this in
# order to adhere to the Django convention of using the empty
# string instead of null, but only if the field accepts the
# empty string.
- if value is None and isinstance(field, Field) and field.empty_strings_allowed:
+ if value is None and field and field.empty_strings_allowed:
value = u''
# Convert 1 or 0 to True or False
- elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)):
+ elif value in (1, 0) and field and field.get_internal_type() in ('BooleanField', 'NullBooleanField'):
value = bool(value)
+ # Force floats to the correct type
+ elif value is not None and field and field.get_internal_type() == 'FloatField':
+ value = float(value)
# Convert floats to decimals
- elif value is not None and isinstance(field, DecimalField):
+ elif value is not None and field and field.get_internal_type() == 'DecimalField':
value = util.typecast_decimal(field.format_number(value))
# cx_Oracle always returns datetime.datetime objects for
# DATE and TIMESTAMP columns, but Django wants to see a
@@ -86,13 +88,9 @@ def query_class(QueryClass, Database):
value = datetime.datetime(value.year, value.month,
value.day, value.hour, value.minute, value.second,
value.fsecond)
- if isinstance(field, DateTimeField):
- # DateTimeField subclasses DateField so must be checked
- # first.
- pass
- elif isinstance(field, DateField):
+ if field and field.get_internal_type() == 'DateField':
value = value.date()
- elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1):
+ elif field and field.get_internal_type() == 'TimeField' or (value.year == 1900 and value.month == value.day == 1):
value = value.time()
elif value.hour == value.minute == value.second == value.microsecond == 0:
value = value.date()
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index 15b0e983ad..071d421b58 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -10,7 +10,7 @@ from django.db.backends import *
from django.db.backends.sqlite3.client import DatabaseClient
from django.db.backends.sqlite3.creation import DatabaseCreation
from django.db.backends.sqlite3.introspection import DatabaseIntrospection
-from django.utils.safestring import SafeString
+from django.utils.safestring import SafeString
try:
try:
@@ -102,6 +102,26 @@ class DatabaseOperations(BaseDatabaseOperations):
second = '%s-12-31 23:59:59.999999'
return [first % value, second % value]
+ def convert_values(self, value, field):
+ """SQLite returns floats when it should be returning decimals,
+ and gets dates and datetimes wrong.
+ For consistency with other backends, coerce when required.
+ """
+ internal_type = field.get_internal_type()
+ if internal_type == 'DecimalField':
+ return util.typecast_decimal(field.format_number(value))
+ elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
+ return int(value)
+ elif internal_type == 'DateField':
+ return util.typecast_date(value)
+ elif internal_type == 'DateTimeField':
+ return util.typecast_timestamp(value)
+ elif internal_type == 'TimeField':
+ return util.typecast_time(value)
+
+ # No field, or the field isn't known to be a decimal or integer
+ return value
+
class DatabaseWrapper(BaseDatabaseWrapper):
# SQLite requires LIKE statements to include an ESCAPE clause if the value