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]) six.reraise(ImproperlyConfigured, ImproperlyConfigured(new_msg), sys.exc_info()[2])
cur.close() cur.close()
return conn 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)) + ');') style.SQL_FIELD(gqn(f.column)) + ');')
return output 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): if options.get("list", False):
return self.show_migration_list(connection, [options['app_label']] if options['app_label'] else None) 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 # Work out which apps have migrations and which do not
executor = MigrationExecutor(connection, self.migration_progress_callback) executor = MigrationExecutor(connection, self.migration_progress_callback)

View File

@ -432,6 +432,13 @@ class BaseDatabaseWrapper(object):
##### Miscellaneous ##### ##### 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 @cached_property
def wrap_database_errors(self): def wrap_database_errors(self):
""" """

View File

@ -371,8 +371,6 @@ class BaseDatabaseCreation(object):
settings.DATABASES[self.connection.alias]["NAME"] = test_database_name settings.DATABASES[self.connection.alias]["NAME"] = test_database_name
self.connection.settings_dict["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. # We report migrate messages at one level lower than that requested.
# This ensures we don't get flooded with messages during testing # This ensures we don't get flooded with messages during testing
# (unless you really ask to be flooded). # (unless you really ask to be flooded).
@ -398,12 +396,6 @@ class BaseDatabaseCreation(object):
return test_database_name 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): def serialize_db_to_string(self):
""" """
Serializes all data in the database into a JSON string. 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 Creating a spatial database for SpatiaLite
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After you've installed SpatiaLite, you'll need to create a number of spatial When running ``manage.py migrate`` with a SQLite or SpatiaLite database, the
metadata tables in your database in order to perform spatial queries. 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, .. versionchanged:: 1.8
like this::
$ spatialite geodjango.db "SELECT InitSpatialMetaData();" Prior to Django 1.8, you had to intialize spatial metadata tables yourself
the SPATIAL_REF_SYS table already contains some row(s) by manually running the "SELECT InitSpatialMetaData();" query.
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.