Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #14648 -- Fixed annotated date querysets when `GeoManager` is u…

…sed. Thanks, codysoyland, for the bug report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16796 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 2918c3de74d1abe571b6c1eeb35e2899c39d880e 1 parent 8e1226b
Justin Bronn authored September 10, 2011
32  django/contrib/gis/db/backends/spatialite/compiler.py
... ...
@@ -1,32 +0,0 @@
1  
-from django.db.backends.util import typecast_timestamp
2  
-from django.db.models.sql import compiler
3  
-from django.db.models.sql.constants import MULTI
4  
-from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler
5  
-
6  
-SQLCompiler = compiler.SQLCompiler
7  
-
8  
-class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler):
9  
-    pass
10  
-
11  
-class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler):
12  
-    pass
13  
-
14  
-class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler):
15  
-    pass
16  
-
17  
-class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler):
18  
-    pass
19  
-
20  
-class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler):
21  
-    pass
22  
-
23  
-class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler):
24  
-    """
25  
-    This is overridden for GeoDjango to properly cast date columns, see #16757.
26  
-    """
27  
-    def results_iter(self):
28  
-        offset = len(self.query.extra_select)
29  
-        for rows in self.execute_sql(MULTI):
30  
-            for row in rows:
31  
-                date = typecast_timestamp(str(row[offset]))
32  
-                yield date
2  django/contrib/gis/db/backends/spatialite/operations.py
@@ -48,7 +48,7 @@ def get_dist_ops(operator):
48 48
     return (SpatiaLiteDistance(operator),)
49 49
 
50 50
 class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
51  
-    compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler'
  51
+    compiler_module = 'django.contrib.gis.db.models.sql.compiler'
52 52
     name = 'spatialite'
53 53
     spatialite = True
54 54
     version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
28  django/contrib/gis/db/models/sql/compiler.py
... ...
@@ -1,7 +1,7 @@
1 1
 from itertools import izip
2  
-from django.db.backends.util import truncate_name
  2
+from django.db.backends.util import truncate_name, typecast_timestamp
3 3
 from django.db.models.sql import compiler
4  
-from django.db.models.sql.constants import TABLE_NAME
  4
+from django.db.models.sql.constants import TABLE_NAME, MULTI
5 5
 from django.db.models.sql.query import get_proxied_model
6 6
 
7 7
 SQLCompiler = compiler.SQLCompiler
@@ -194,7 +194,7 @@ def resolve_columns(self, row, fields=()):
194 194
             # We resolve the rest of the columns if we're on Oracle or if
195 195
             # the `geo_values` attribute is defined.
196 196
             for value, field in map(None, row[index_start:], fields):
197  
-                values.append(self.query.convert_values(value, field, connection=self.connection))
  197
+                values.append(self.query.convert_values(value, field, self.connection))
198 198
         else:
199 199
             values.extend(row[index_start:])
200 200
         return tuple(values)
@@ -275,4 +275,24 @@ class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler):
275 275
     pass
276 276
 
277 277
 class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler):
278  
-    pass
  278
+    """
  279
+    This is overridden for GeoDjango to properly cast date columns, since
  280
+    `GeoQuery.resolve_columns` is used for spatial values.
  281
+    See #14648, #16757.
  282
+    """
  283
+    def results_iter(self):
  284
+        if self.connection.ops.oracle:
  285
+            from django.db.models.fields import DateTimeField
  286
+            fields = [DateTimeField()]
  287
+        else:
  288
+            needs_string_cast = self.connection.features.needs_datetime_string_cast
  289
+
  290
+        offset = len(self.query.extra_select)
  291
+        for rows in self.execute_sql(MULTI):
  292
+            for row in rows:
  293
+                date = row[offset]
  294
+                if self.connection.ops.oracle:
  295
+                    date = self.resolve_columns(row, fields)[offset]
  296
+                elif needs_string_cast:
  297
+                    date = typecast_timestamp(str(date))
  298
+                yield date
BIN  django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz
Binary file not shown
1  django/contrib/gis/tests/relatedapp/models.py
@@ -36,6 +36,7 @@ def __unicode__(self): return self.name
36 36
 # These use the GeoManager but do not have any geographic fields.
37 37
 class Author(models.Model):
38 38
     name = models.CharField(max_length=100)
  39
+    dob = models.DateField()
39 40
     objects = models.GeoManager()
40 41
 
41 42
 class Article(models.Model):
8  django/contrib/gis/tests/relatedapp/tests.py
... ...
@@ -1,3 +1,4 @@
  1
+from datetime import date
1 2
 from django.test import TestCase
2 3
 
3 4
 from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint
@@ -281,4 +282,11 @@ def test15_invalid_select_related(self):
281 282
         # evaluated as list generation swallows TypeError in CPython.
282 283
         sql = str(qs.query)
283 284
 
  285
+    def test16_annotated_date_queryset(self):
  286
+        "Ensure annotated date querysets work if spatial backend is used.  See #14648."
  287
+        birth_years = [dt.year for dt in 
  288
+                       list(Author.objects.annotate(num_books=Count('books')).dates('dob', 'year'))]
  289
+        birth_years.sort()
  290
+        self.assertEqual([1950, 1974], birth_years)
  291
+
284 292
     # TODO: Related tests for KML, GML, and distance lookups.

0 notes on commit 2918c3d

Please sign in to comment.
Something went wrong with that request. Please try again.