mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +00:00 
			
		
		
		
	Fixed #14648 -- Fixed annotated date querysets when GeoManager is used.  Thanks, codysoyland, for the bug report.
				
					
				
			git-svn-id: http://code.djangoproject.com/svn/django/trunk@16796 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -1,32 +0,0 @@ | ||||
| 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 | ||||
| @@ -48,7 +48,7 @@ def get_dist_ops(operator): | ||||
|     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+)') | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| 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 | ||||
| @@ -194,7 +194,7 @@ class GeoSQLCompiler(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) | ||||
| @@ -275,4 +275,24 @@ class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler): | ||||
|     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 | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -36,6 +36,7 @@ class Parcel(models.Model): | ||||
| # 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): | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| from datetime import date | ||||
| from django.test import TestCase | ||||
|  | ||||
| from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint | ||||
| @@ -281,4 +282,11 @@ class RelatedGeoModelTest(TestCase): | ||||
|         # 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. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user