diff --git a/django/contrib/gis/db/models/sql/conversion.py b/django/contrib/gis/db/models/sql/conversion.py index afc1053790d..acc277ed624 100644 --- a/django/contrib/gis/db/models/sql/conversion.py +++ b/django/contrib/gis/db/models/sql/conversion.py @@ -4,6 +4,8 @@ database. """ from __future__ import unicode_literals +from decimal import Decimal + from django.contrib.gis.db.models.fields import GeoSelectFormatMixin from django.contrib.gis.geometry.backend import Geometry from django.contrib.gis.measure import Area, Distance @@ -27,6 +29,10 @@ class AreaField(BaseField): def from_db_value(self, value, expression, connection, context): if connection.features.interprets_empty_strings_as_nulls and value == '': value = None + # If the database returns a Decimal, convert it to a float as expected + # by the Python geometric objects. + if isinstance(value, Decimal): + value = float(value) # If the units are known, convert value into area measure. if value is not None and self.area_att: value = Area(**{self.area_att: value}) diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index 0e7381a9728..fd2b1a5d40c 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -353,7 +353,10 @@ Backwards incompatible changes in 1.10 Database backend API -------------------- -* ... +* GIS's ``AreaField`` uses an unspecified underlying numeric type that could in + practice be any numeric Python type. ``decimal.Decimal`` values retrieved + from the database are now converted to ``float`` to make it easier to combine + them with values used by the GIS libraries. ``select_related()`` prohibits non-relational fields for nested relations ------------------------------------------------------------------------- @@ -515,6 +518,10 @@ Miscellaneous argument of the ``render_options()`` method is also removed, making ``selected_choices`` the first argument. +* On Oracle/GIS, the :class:`~django.contrib.gis.db.models.functions.Area` + aggregate function now returns a ``float`` instead of ``decimal.Decimal``. + (It's still wrapped in a measure of square meters.) + .. _deprecated-features-1.10: Features deprecated in 1.10 diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py index aeb1007c565..344fa03e61d 100644 --- a/tests/gis_tests/geoapp/test_functions.py +++ b/tests/gis_tests/geoapp/test_functions.py @@ -240,7 +240,9 @@ class GISFunctionsTests(TestCase): CountryWebMercator.objects.create(name=c.name, mpoly=c.mpoly) # Test in projected coordinate system qs = CountryWebMercator.objects.annotate(area_sum=Sum(functions.Area('mpoly'))) - for c in qs: + # Some backends (e.g. Oracle) cannot group by multipolygon values, so + # defer such fields in the aggregation query. + for c in qs.defer('mpoly'): result = c.area_sum # If the result is a measure object, get value. if isinstance(result, Area):