Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[1.3.X] Fixed #16408 -- Fixed conversion of dates, and other problems…

… with the SpatiaLite backend.

Backport of r16749 and r16750 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.3.X@16751 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 52279a41137e13ab0056728a730b5d6ecf132841 1 parent 1f7c6c0
@jbronn jbronn authored
View
10 django/contrib/gis/db/backends/spatialite/base.py
@@ -2,15 +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 DatabaseWrapper as SqliteDatabaseWrapper, \
- _sqlite_extract, _sqlite_date_trunc, _sqlite_regexp
+from django.db.backends.sqlite3.base import (
+ _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):
@@ -51,6 +52,7 @@ def _cursor(self):
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 ##
View
32 django/contrib/gis/db/backends/spatialite/compiler.py
@@ -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
View
47 django/contrib/gis/db/backends/spatialite/creation.py
@@ -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,64 @@ def create_test_db(self, verbosity=1, autoclobber=False):
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
+
# 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()
View
2  django/contrib/gis/db/backends/spatialite/operations.py
@@ -48,7 +48,7 @@ def get_dist_ops(operator):
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+)')
View
2  django/contrib/gis/db/models/sql/compiler.py
@@ -202,7 +202,7 @@ def resolve_columns(self, row, fields=()):
#### 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
View
1  django/contrib/gis/tests/geoapp/models.py
@@ -19,6 +19,7 @@ def __unicode__(self): return self.name
# 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):
View
14 django/contrib/gis/tests/geoapp/test_regress.py
@@ -1,9 +1,10 @@
-import os, unittest
+from datetime import datetime
from django.contrib.gis.tests.utils import no_mysql, no_oracle, no_postgis, 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 @@ def test03_extent(self):
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])

0 comments on commit 52279a4

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