Commits

Anonymous committed 0014630

[1.3.X] Fixed #14648 -- Fixed annotated date querysets when `GeoManager` is used. Thanks, codysoyland, for the bug report.

Backport of r16796 from trunk.

  • Participants
  • Parent commits 4960b85
  • Branches releases/1.3.X

Comments (0)

Files changed (6)

File django/contrib/gis/db/backends/spatialite/compiler.py

-from django.db.backends.util import typecast_timestamp
-from django.db.models.sql import compiler
-from django.db.models.sql.constants import MULTI
-from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler
-
-SQLCompiler = compiler.SQLCompiler
-
-class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler):
-    pass
-
-class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler):
-    pass
-
-class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler):
-    pass
-
-class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler):
-    pass
-
-class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler):
-    pass
-
-class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler):
-    """
-    This is overridden for GeoDjango to properly cast date columns, see #16757.
-    """
-    def results_iter(self):
-        offset = len(self.query.extra_select)
-        for rows in self.execute_sql(MULTI):
-            for row in rows:
-                date = typecast_timestamp(str(row[offset]))
-                yield date

File django/contrib/gis/db/backends/spatialite/operations.py

     return (SpatiaLiteDistance(operator),)
 
 class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
-    compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler'
+    compiler_module = 'django.contrib.gis.db.models.sql.compiler'
     name = 'spatialite'
     spatialite = True
     version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')

File django/contrib/gis/db/models/sql/compiler.py

 from itertools import izip
-from django.db.backends.util import truncate_name
+from django.db.backends.util import truncate_name, typecast_timestamp
 from django.db.models.sql import compiler
-from django.db.models.sql.constants import TABLE_NAME
+from django.db.models.sql.constants import TABLE_NAME, MULTI
 from django.db.models.sql.query import get_proxied_model
 
 SQLCompiler = compiler.SQLCompiler
             # We resolve the rest of the columns if we're on Oracle or if
             # the `geo_values` attribute is defined.
             for value, field in map(None, row[index_start:], fields):
-                values.append(self.query.convert_values(value, field, connection=self.connection))
+                values.append(self.query.convert_values(value, field, self.connection))
         else:
             values.extend(row[index_start:])
         return tuple(values)
     pass
 
 class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler):
-    pass
+    """
+    This is overridden for GeoDjango to properly cast date columns, since
+    `GeoQuery.resolve_columns` is used for spatial values.
+    See #14648, #16757.
+    """
+    def results_iter(self):
+        if self.connection.ops.oracle:
+            from django.db.models.fields import DateTimeField
+            fields = [DateTimeField()]
+        else:
+            needs_string_cast = self.connection.features.needs_datetime_string_cast
+
+        offset = len(self.query.extra_select)
+        for rows in self.execute_sql(MULTI):
+            for row in rows:
+                date = row[offset]
+                if self.connection.ops.oracle:
+                    date = self.resolve_columns(row, fields)[offset]
+                elif needs_string_cast:
+                    date = typecast_timestamp(str(date))
+                yield date

File django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz

Binary file modified.

File django/contrib/gis/tests/relatedapp/models.py

 # These use the GeoManager but do not have any geographic fields.
 class Author(models.Model):
     name = models.CharField(max_length=100)
+    dob = models.DateField()
     objects = models.GeoManager()
 
 class Article(models.Model):

File django/contrib/gis/tests/relatedapp/tests.py

+from datetime import date
 from django.test import TestCase
 
 from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint
         # evaluated as list generation swallows TypeError in CPython.
         sql = str(qs.query)
 
+    def test16_annotated_date_queryset(self):
+        "Ensure annotated date querysets work if spatial backend is used.  See #14648."
+        birth_years = [dt.year for dt in 
+                       list(Author.objects.annotate(num_books=Count('books')).dates('dob', 'year'))]
+        birth_years.sort()
+        self.assertEqual([1950, 1974], birth_years)
+
     # TODO: Related tests for KML, GML, and distance lookups.