diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2009-01-15 11:06:34 +0000 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2009-01-15 11:06:34 +0000 |
| commit | cc4e4d9aee0b3ebfb45bee01aec79edc9e144c78 (patch) | |
| tree | 2cdba846a105d406ecceff2c02e071c50502d487 /django/db/backends | |
| parent | 50a293a0c31e7325ebd520338f9c8881f951d8a7 (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__.py | 23 | ||||
| -rw-r--r-- | django/db/backends/mysql/base.py | 1 | ||||
| -rw-r--r-- | django/db/backends/oracle/query.py | 20 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/base.py | 22 |
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 |
