Author: jbronn
Date: 2011-09-09 15:34:23 -0700 (Fri, 09 Sep 2011)
New Revision: 16749

Added:
   django/trunk/django/contrib/gis/db/backends/spatialite/compiler.py
Modified:
   django/trunk/django/contrib/gis/db/backends/spatialite/base.py
   django/trunk/django/contrib/gis/db/backends/spatialite/creation.py
   django/trunk/django/contrib/gis/db/backends/spatialite/operations.py
   django/trunk/django/contrib/gis/db/models/sql/compiler.py
   django/trunk/django/contrib/gis/tests/geoapp/models.py
   django/trunk/django/contrib/gis/tests/geoapp/test_regress.py
Log:
Fixed #16408 -- Fixed conversion of dates, and other problems with the 
SpatiaLite backend.

Modified: django/trunk/django/contrib/gis/db/backends/spatialite/base.py
===================================================================
--- django/trunk/django/contrib/gis/db/backends/spatialite/base.py      
2011-09-09 22:33:28 UTC (rev 16748)
+++ django/trunk/django/contrib/gis/db/backends/spatialite/base.py      
2011-09-09 22:34:23 UTC (rev 16749)
@@ -2,16 +2,16 @@
 from django.conf import settings
 
 from django.core.exceptions import ImproperlyConfigured
-from django.db.backends.sqlite3.base import *
 from django.db.backends.sqlite3.base import (
-    _sqlite_extract, _sqlite_date_trunc, _sqlite_regexp,
-    DatabaseWrapper as SqliteDatabaseWrapper)
+    _sqlite_extract, _sqlite_date_trunc, _sqlite_regexp, 
_sqlite_format_dtdelta,
+    connection_created, Database, DatabaseWrapper as SQLiteDatabaseWrapper,
+    SQLiteCursorWrapper)
 from django.contrib.gis.db.backends.spatialite.client import SpatiaLiteClient
 from django.contrib.gis.db.backends.spatialite.creation import 
SpatiaLiteCreation
 from django.contrib.gis.db.backends.spatialite.introspection import 
SpatiaLiteIntrospection
 from django.contrib.gis.db.backends.spatialite.operations import 
SpatiaLiteOperations
 
-class DatabaseWrapper(SqliteDatabaseWrapper):
+class DatabaseWrapper(SQLiteDatabaseWrapper):
     def __init__(self, *args, **kwargs):
         # Before we get too far, make sure pysqlite 2.5+ is installed.
         if Database.version_info < (2, 5, 0):
@@ -52,6 +52,7 @@
             self.connection.create_function("django_extract", 2, 
_sqlite_extract)
             self.connection.create_function("django_date_trunc", 2, 
_sqlite_date_trunc)
             self.connection.create_function("regexp", 2, _sqlite_regexp)
+            self.connection.create_function("django_format_dtdelta", 5, 
_sqlite_format_dtdelta)
             connection_created.send(sender=self.__class__, connection=self)
 
             ## From here on, customized for GeoDjango ##

Added: django/trunk/django/contrib/gis/db/backends/spatialite/compiler.py
===================================================================
--- django/trunk/django/contrib/gis/db/backends/spatialite/compiler.py          
                (rev 0)
+++ django/trunk/django/contrib/gis/db/backends/spatialite/compiler.py  
2011-09-09 22:34:23 UTC (rev 16749)
@@ -0,0 +1,32 @@
+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

Modified: django/trunk/django/contrib/gis/db/backends/spatialite/creation.py
===================================================================
--- django/trunk/django/contrib/gis/db/backends/spatialite/creation.py  
2011-09-09 22:33:28 UTC (rev 16748)
+++ django/trunk/django/contrib/gis/db/backends/spatialite/creation.py  
2011-09-09 22:34:23 UTC (rev 16749)
@@ -3,7 +3,6 @@
 from django.core.cache import get_cache
 from django.core.cache.backends.db import BaseDatabaseCache
 from django.core.exceptions import ImproperlyConfigured
-from django.core.management import call_command
 from django.db.backends.sqlite3.creation import DatabaseCreation
 
 class SpatiaLiteCreation(DatabaseCreation):
@@ -16,26 +15,65 @@
         This method is overloaded to load up the SpatiaLite initialization
         SQL prior to calling the `syncdb` command.
         """
+        # Don't import django.core.management if it isn't needed.
+        from django.core.management import call_command
+
+        test_database_name = self._get_test_db_name()
+
         if verbosity >= 1:
-            print "Creating test database '%s'..." % self.connection.alias
+            test_db_repr = ''
+            if verbosity >= 2:
+                test_db_repr = " ('%s')" % test_database_name
+            print "Creating test database for alias '%s'%s..." % 
(self.connection.alias, test_db_repr)
 
-        test_database_name = self._create_test_db(verbosity, autoclobber)
+        self._create_test_db(verbosity, autoclobber)
 
         self.connection.close()
+        self.connection.settings_dict["NAME"] = test_database_name
 
-        self.connection.settings_dict["NAME"] = test_database_name
         # Confirm the feature set of the test database
         self.connection.features.confirm()
+
         # Need to load the SpatiaLite initialization SQL before running 
`syncdb`.
         self.load_spatialite_sql()
         call_command('syncdb', verbosity=verbosity, interactive=False, 
database=self.connection.alias)
 
+        # Report syncdb messages at one level lower than that requested.
+        # This ensures we don't get flooded with messages during testing
+        # (unless you really ask to be flooded)
+        call_command('syncdb',
+            verbosity=max(verbosity - 1, 0),
+            interactive=False,
+            database=self.connection.alias,
+            load_initial_data=False)
+
+        # We need to then do a flush to ensure that any data installed by
+        # custom SQL has been removed. The only test data should come from
+        # test fixtures, or autogenerated from post_syncdb triggers.
+        # This has the side effect of loading initial data (which was
+        # intentionally skipped in the syncdb).
+        call_command('flush',
+            verbosity=max(verbosity - 1, 0),
+            interactive=False,
+            database=self.connection.alias)
+
+        # One effect of calling syncdb followed by flush is that the id of the
+        # default site may or may not be 1, depending on how the sequence was
+        # reset.  If the sites app is loaded, then we coerce it.
+        from django.db.models import get_model
+        Site = get_model('sites', 'Site')
+        if Site is not None and 
Site.objects.using(self.connection.alias).count() == 1:
+            
Site.objects.using(self.connection.alias).update(id=settings.SITE_ID)
+
+        from django.core.cache import get_cache
+        from django.core.cache.backends.db import BaseDatabaseCache
         for cache_alias in settings.CACHES:
             cache = get_cache(cache_alias)
             if isinstance(cache, BaseDatabaseCache):
                 from django.db import router
                 if router.allow_syncdb(self.connection.alias, 
cache.cache_model_class):
                     call_command('createcachetable', cache._table, 
database=self.connection.alias)
+
         # Get a cursor (even though we don't need one yet). This has
         # the side effect of initializing the test database.
         cursor = self.connection.cursor()

Modified: django/trunk/django/contrib/gis/db/backends/spatialite/operations.py
===================================================================
--- django/trunk/django/contrib/gis/db/backends/spatialite/operations.py        
2011-09-09 22:33:28 UTC (rev 16748)
+++ django/trunk/django/contrib/gis/db/backends/spatialite/operations.py        
2011-09-09 22:34:23 UTC (rev 16749)
@@ -48,7 +48,7 @@
     return (SpatiaLiteDistance(operator),)
 
 class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
-    compiler_module = 'django.contrib.gis.db.models.sql.compiler'
+    compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler'
     name = 'spatialite'
     spatialite = True
     version_regex = 
re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')

Modified: django/trunk/django/contrib/gis/db/models/sql/compiler.py
===================================================================
--- django/trunk/django/contrib/gis/db/models/sql/compiler.py   2011-09-09 
22:33:28 UTC (rev 16748)
+++ django/trunk/django/contrib/gis/db/models/sql/compiler.py   2011-09-09 
22:34:23 UTC (rev 16749)
@@ -202,7 +202,7 @@
     #### Routines unique to GeoQuery ####
     def get_extra_select_format(self, alias):
         sel_fmt = '%s'
-        if alias in self.query.custom_select:
+        if hasattr(self.query, 'custom_select') and alias in 
self.query.custom_select:
             sel_fmt = sel_fmt % self.query.custom_select[alias]
         return sel_fmt
 

Modified: django/trunk/django/contrib/gis/tests/geoapp/models.py
===================================================================
--- django/trunk/django/contrib/gis/tests/geoapp/models.py      2011-09-09 
22:33:28 UTC (rev 16748)
+++ django/trunk/django/contrib/gis/tests/geoapp/models.py      2011-09-09 
22:34:23 UTC (rev 16749)
@@ -19,6 +19,7 @@
 # This is an inherited model from City
 class PennsylvaniaCity(City):
     county = models.CharField(max_length=30)
+    founded = models.DateTimeField(null=True)
     objects = models.GeoManager() # TODO: This should be implicitly inherited.
 
 class State(models.Model):

Modified: django/trunk/django/contrib/gis/tests/geoapp/test_regress.py
===================================================================
--- django/trunk/django/contrib/gis/tests/geoapp/test_regress.py        
2011-09-09 22:33:28 UTC (rev 16748)
+++ django/trunk/django/contrib/gis/tests/geoapp/test_regress.py        
2011-09-09 22:34:23 UTC (rev 16749)
@@ -1,9 +1,10 @@
-import unittest
+from datetime import datetime
 from django.contrib.gis.tests.utils import no_mysql, no_spatialite
 from django.contrib.gis.shortcuts import render_to_kmz
-from models import City
+from django.test import TestCase
+from models import City, PennsylvaniaCity
 
-class GeoRegressionTests(unittest.TestCase):
+class GeoRegressionTests(TestCase):
 
     def test01_update(self):
         "Testing GeoQuerySet.update(), see #10411."
@@ -35,3 +36,10 @@
         extent = City.objects.filter(name='Pueblo').extent()
         for ref_val, val in zip(ref_ext, extent):
             self.assertAlmostEqual(ref_val, val, 4)
+
+    def test04_unicode_date(self):
+        "Testing dates are converted properly, even on SpatiaLite, see #16408."
+        founded = datetime(1857, 5, 23)
+        mansfield = PennsylvaniaCity.objects.create(name='Mansfield', 
county='Tioga', point='POINT(-77.071445 41.823881)',
+                                                    founded=founded)
+        self.assertEqual(founded, PennsylvaniaCity.objects.dates('founded', 
'day')[0])

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to