Browse Source

Fixed #20968 -- Checked Spatialite metadata before migrations

Thanks Kenial S. Lee for the initial patch and Tim Graham for
the review.
Claude Paroz 10 years ago
parent
commit
8f97413fae

+ 9 - 0
django/contrib/gis/db/backends/spatialite/base.py

@@ -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)

+ 0 - 8
django/contrib/gis/db/backends/spatialite/creation.py

@@ -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)

+ 2 - 0
django/core/management/commands/migrate.py

@@ -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)
 

+ 7 - 0
django/db/backends/__init__.py

@@ -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):
         """

+ 0 - 8
django/db/backends/creation.py

@@ -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.

+ 6 - 29
docs/ref/contrib/gis/install/spatialite.txt

@@ -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.