Commit 52279a41 authored by Justin Bronn's avatar Justin Bronn
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
parent 1f7c6c01
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -2,15 +2,16 @@ from ctypes.util import find_library
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 @@ class DatabaseWrapper(SqliteDatabaseWrapper):
            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 ##
+32 −0
Original line number Diff line number Diff line
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
+42 −5
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@ from django.conf import settings
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 @@ class SpatiaLiteCreation(DatabaseCreation):
        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()
+1 −1
Original line number Diff line number Diff line
@@ -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+)')
+1 −1
Original line number Diff line number Diff line
@@ -202,7 +202,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
    #### 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

Loading