Fixed #20968 -- Checked Spatialite metadata before migrations

Thanks Kenial S. Lee for the initial patch and Tim Graham for
the review.
This commit is contained in:
Claude Paroz 2014-12-06 11:05:54 +01:00
parent 1aa41dd000
commit 8f97413fae
6 changed files with 24 additions and 45 deletions

View File

@ -79,3 +79,12 @@ class DatabaseWrapper(SQLiteDatabaseWrapper):
six.reraise(ImproperlyConfigured, ImproperlyConfigured(new_msg), sys.exc_info()[2])
cur.close()
return conn
def prepare_database(self):
super(DatabaseWrapper, self).prepare_database()
# Check if spatial metadata have been initialized in the database
with self.cursor() as cursor:
cursor.execute("PRAGMA table_info(geometry_columns);")
if cursor.fetchall() == []:
arg = "1" if self.features.supports_initspatialmetadata_in_one_transaction else ""
cursor.execute("SELECT InitSpatialMetaData(%s)" % arg)

View File

@ -30,11 +30,3 @@ class SpatiaLiteCreation(DatabaseCreation):
style.SQL_FIELD(gqn(f.column)) + ');')
return output
def _create_test_db_pre_migrate_sql(self):
"""
Creates the spatial metadata tables.
"""
cur = self.connection._cursor()
arg = "1" if self.connection.features.supports_initspatialmetadata_in_one_transaction else ""
cur.execute("SELECT InitSpatialMetaData(%s)" % arg)

View File

@ -64,6 +64,8 @@ class Command(BaseCommand):
if options.get("list", False):
return self.show_migration_list(connection, [options['app_label']] if options['app_label'] else None)
# Hook for backends needing any database preparation
connection.prepare_database()
# Work out which apps have migrations and which do not
executor = MigrationExecutor(connection, self.migration_progress_callback)

View File

@ -432,6 +432,13 @@ class BaseDatabaseWrapper(object):
##### Miscellaneous #####
def prepare_database(self):
"""
Hook to do any database check or preparation, generally called before
migrating a project or an app.
"""
pass
@cached_property
def wrap_database_errors(self):
"""

View File

@ -371,8 +371,6 @@ class BaseDatabaseCreation(object):
settings.DATABASES[self.connection.alias]["NAME"] = test_database_name
self.connection.settings_dict["NAME"] = test_database_name
self._create_test_db_pre_migrate_sql()
# We report migrate 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).
@ -398,12 +396,6 @@ class BaseDatabaseCreation(object):
return test_database_name
def _create_test_db_pre_migrate_sql(self):
"""
Hook for databases to load SQL before creating the test DB.
"""
pass
def serialize_db_to_string(self):
"""
Serializes all data in the database into a JSON string.

View File

@ -211,34 +211,11 @@ following to your ``settings.py``::
Creating a spatial database for SpatiaLite
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After you've installed SpatiaLite, you'll need to create a number of spatial
metadata tables in your database in order to perform spatial queries.
When running ``manage.py migrate`` with a SQLite or SpatiaLite database, the
database file will be automatically created if it doesn't exist. Django will
also ensure that the spatial metadata are initialized in the database.
Use the ``spatialite`` utility to call the ``InitSpatialMetaData()`` function,
like this::
.. versionchanged:: 1.8
$ spatialite geodjango.db "SELECT InitSpatialMetaData();"
the SPATIAL_REF_SYS table already contains some row(s)
InitSpatiaMetaData ()error:"table spatial_ref_sys already exists"
0
You can safely ignore the error messages shown.
.. note::
The parameter ``geodjango.db`` is the *filename* of the SQLite database
you want to use. Use the same in the :setting:`DATABASES` ``"name"`` key
inside your ``settings.py``.
.. note::
When running ``manage.py migrate`` with a SQLite (or SpatiaLite) database,
the database file will be automatically created if it doesn't exist. In
this case, if your models contain any geometry columns, you'll see this
error::
CreateSpatialIndex() error: "no such table: geometry_columns"
It's because the table creation queries are executed without spatial
metadata tables. To avoid this, make the database file before executing
``manage.py migrate`` as described above.
Prior to Django 1.8, you had to intialize spatial metadata tables yourself
by manually running the "SELECT InitSpatialMetaData();" query.