Code

Ticket #16408: 16408.3.diff

File 16408.3.diff, 10.0 KB (added by jbronn, 3 years ago)
Line 
1diff -r d3a1dd01e8da django/contrib/gis/db/backends/spatialite/base.py
2--- a/django/contrib/gis/db/backends/spatialite/base.py Fri Sep 09 19:51:06 2011 +0000
3+++ b/django/contrib/gis/db/backends/spatialite/base.py Fri Sep 09 15:20:46 2011 -0700
4@@ -2,16 +2,16 @@
5 from django.conf import settings
6 
7 from django.core.exceptions import ImproperlyConfigured
8-from django.db.backends.sqlite3.base import *
9 from django.db.backends.sqlite3.base import (
10-    _sqlite_extract, _sqlite_date_trunc, _sqlite_regexp,
11-    DatabaseWrapper as SqliteDatabaseWrapper)
12+    _sqlite_extract, _sqlite_date_trunc, _sqlite_regexp, _sqlite_format_dtdelta,
13+    connection_created, Database, DatabaseWrapper as SQLiteDatabaseWrapper,
14+    SQLiteCursorWrapper)
15 from django.contrib.gis.db.backends.spatialite.client import SpatiaLiteClient
16 from django.contrib.gis.db.backends.spatialite.creation import SpatiaLiteCreation
17 from django.contrib.gis.db.backends.spatialite.introspection import SpatiaLiteIntrospection
18 from django.contrib.gis.db.backends.spatialite.operations import SpatiaLiteOperations
19 
20-class DatabaseWrapper(SqliteDatabaseWrapper):
21+class DatabaseWrapper(SQLiteDatabaseWrapper):
22     def __init__(self, *args, **kwargs):
23         # Before we get too far, make sure pysqlite 2.5+ is installed.
24         if Database.version_info < (2, 5, 0):
25@@ -52,6 +52,7 @@
26             self.connection.create_function("django_extract", 2, _sqlite_extract)
27             self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
28             self.connection.create_function("regexp", 2, _sqlite_regexp)
29+            self.connection.create_function("django_format_dtdelta", 5, _sqlite_format_dtdelta)
30             connection_created.send(sender=self.__class__, connection=self)
31 
32             ## From here on, customized for GeoDjango ##
33diff -r d3a1dd01e8da django/contrib/gis/db/backends/spatialite/compiler.py
34--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
35+++ b/django/contrib/gis/db/backends/spatialite/compiler.py     Fri Sep 09 15:20:46 2011 -0700
36@@ -0,0 +1,32 @@
37+from django.db.backends.util import typecast_timestamp
38+from django.db.models.sql import compiler
39+from django.db.models.sql.constants import MULTI
40+from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler
41+
42+SQLCompiler = compiler.SQLCompiler
43+
44+class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler):
45+    pass
46+
47+class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler):
48+    pass
49+
50+class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler):
51+    pass
52+
53+class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler):
54+    pass
55+
56+class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler):
57+    pass
58+
59+class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler):
60+    """
61+    This is overridden for GeoDjango to properly cast date columns, see #16757.
62+    """
63+    def results_iter(self):
64+        offset = len(self.query.extra_select)
65+        for rows in self.execute_sql(MULTI):
66+            for row in rows:
67+                date = typecast_timestamp(str(row[offset]))
68+                yield date
69diff -r d3a1dd01e8da django/contrib/gis/db/backends/spatialite/creation.py
70--- a/django/contrib/gis/db/backends/spatialite/creation.py     Fri Sep 09 19:51:06 2011 +0000
71+++ b/django/contrib/gis/db/backends/spatialite/creation.py     Fri Sep 09 15:20:46 2011 -0700
72@@ -3,7 +3,6 @@
73 from django.core.cache import get_cache
74 from django.core.cache.backends.db import BaseDatabaseCache
75 from django.core.exceptions import ImproperlyConfigured
76-from django.core.management import call_command
77 from django.db.backends.sqlite3.creation import DatabaseCreation
78 
79 class SpatiaLiteCreation(DatabaseCreation):
80@@ -16,26 +15,65 @@
81         This method is overloaded to load up the SpatiaLite initialization
82         SQL prior to calling the `syncdb` command.
83         """
84+        # Don't import django.core.management if it isn't needed.
85+        from django.core.management import call_command
86+
87+        test_database_name = self._get_test_db_name()
88+
89         if verbosity >= 1:
90-            print "Creating test database '%s'..." % self.connection.alias
91+            test_db_repr = ''
92+            if verbosity >= 2:
93+                test_db_repr = " ('%s')" % test_database_name
94+            print "Creating test database for alias '%s'%s..." % (self.connection.alias, test_db_repr)
95 
96-        test_database_name = self._create_test_db(verbosity, autoclobber)
97+        self._create_test_db(verbosity, autoclobber)
98 
99         self.connection.close()
100+        self.connection.settings_dict["NAME"] = test_database_name
101 
102-        self.connection.settings_dict["NAME"] = test_database_name
103         # Confirm the feature set of the test database
104         self.connection.features.confirm()
105+
106         # Need to load the SpatiaLite initialization SQL before running `syncdb`.
107         self.load_spatialite_sql()
108         call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias)
109 
110+        # Report syncdb messages at one level lower than that requested.
111+        # This ensures we don't get flooded with messages during testing
112+        # (unless you really ask to be flooded)
113+        call_command('syncdb',
114+            verbosity=max(verbosity - 1, 0),
115+            interactive=False,
116+            database=self.connection.alias,
117+            load_initial_data=False)
118+
119+        # We need to then do a flush to ensure that any data installed by
120+        # custom SQL has been removed. The only test data should come from
121+        # test fixtures, or autogenerated from post_syncdb triggers.
122+        # This has the side effect of loading initial data (which was
123+        # intentionally skipped in the syncdb).
124+        call_command('flush',
125+            verbosity=max(verbosity - 1, 0),
126+            interactive=False,
127+            database=self.connection.alias)
128+
129+        # One effect of calling syncdb followed by flush is that the id of the
130+        # default site may or may not be 1, depending on how the sequence was
131+        # reset.  If the sites app is loaded, then we coerce it.
132+        from django.db.models import get_model
133+        Site = get_model('sites', 'Site')
134+        if Site is not None and Site.objects.using(self.connection.alias).count() == 1:
135+            Site.objects.using(self.connection.alias).update(id=settings.SITE_ID)
136+
137+        from django.core.cache import get_cache
138+        from django.core.cache.backends.db import BaseDatabaseCache
139         for cache_alias in settings.CACHES:
140             cache = get_cache(cache_alias)
141             if isinstance(cache, BaseDatabaseCache):
142                 from django.db import router
143                 if router.allow_syncdb(self.connection.alias, cache.cache_model_class):
144                     call_command('createcachetable', cache._table, database=self.connection.alias)
145+
146         # Get a cursor (even though we don't need one yet). This has
147         # the side effect of initializing the test database.
148         cursor = self.connection.cursor()
149diff -r d3a1dd01e8da django/contrib/gis/db/backends/spatialite/operations.py
150--- a/django/contrib/gis/db/backends/spatialite/operations.py   Fri Sep 09 19:51:06 2011 +0000
151+++ b/django/contrib/gis/db/backends/spatialite/operations.py   Fri Sep 09 15:20:46 2011 -0700
152@@ -48,7 +48,7 @@
153     return (SpatiaLiteDistance(operator),)
154 
155 class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
156-    compiler_module = 'django.contrib.gis.db.models.sql.compiler'
157+    compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler'
158     name = 'spatialite'
159     spatialite = True
160     version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
161diff -r d3a1dd01e8da django/contrib/gis/db/models/sql/compiler.py
162--- a/django/contrib/gis/db/models/sql/compiler.py      Fri Sep 09 19:51:06 2011 +0000
163+++ b/django/contrib/gis/db/models/sql/compiler.py      Fri Sep 09 15:20:46 2011 -0700
164@@ -202,7 +202,7 @@
165     #### Routines unique to GeoQuery ####
166     def get_extra_select_format(self, alias):
167         sel_fmt = '%s'
168-        if alias in self.query.custom_select:
169+        if hasattr(self.query, 'custom_select') and alias in self.query.custom_select:
170             sel_fmt = sel_fmt % self.query.custom_select[alias]
171         return sel_fmt
172 
173diff -r d3a1dd01e8da django/contrib/gis/tests/geoapp/models.py
174--- a/django/contrib/gis/tests/geoapp/models.py Fri Sep 09 19:51:06 2011 +0000
175+++ b/django/contrib/gis/tests/geoapp/models.py Fri Sep 09 15:20:46 2011 -0700
176@@ -19,6 +19,7 @@
177 # This is an inherited model from City
178 class PennsylvaniaCity(City):
179     county = models.CharField(max_length=30)
180+    founded = models.DateTimeField(null=True)
181     objects = models.GeoManager() # TODO: This should be implicitly inherited.
182 
183 class State(models.Model):
184diff -r d3a1dd01e8da django/contrib/gis/tests/geoapp/test_regress.py
185--- a/django/contrib/gis/tests/geoapp/test_regress.py   Fri Sep 09 19:51:06 2011 +0000
186+++ b/django/contrib/gis/tests/geoapp/test_regress.py   Fri Sep 09 15:20:46 2011 -0700
187@@ -1,9 +1,10 @@
188-import unittest
189+from datetime import datetime
190 from django.contrib.gis.tests.utils import no_mysql, no_spatialite
191 from django.contrib.gis.shortcuts import render_to_kmz
192-from models import City
193+from django.test import TestCase
194+from models import City, PennsylvaniaCity
195 
196-class GeoRegressionTests(unittest.TestCase):
197+class GeoRegressionTests(TestCase):
198 
199     def test01_update(self):
200         "Testing GeoQuerySet.update(), see #10411."
201@@ -35,3 +36,10 @@
202         extent = City.objects.filter(name='Pueblo').extent()
203         for ref_val, val in zip(ref_ext, extent):
204             self.assertAlmostEqual(ref_val, val, 4)
205+
206+    def test04_unicode_date(self):
207+        "Testing dates are converted properly, even on SpatiaLite, see #16408."
208+        founded = datetime(1857, 5, 23)
209+        mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)',
210+                                                    founded=founded)
211+        self.assertEqual(founded, PennsylvaniaCity.objects.dates('founded', 'day')[0])