Commit c3228ef3 authored by Claude Paroz's avatar Claude Paroz
Browse files

[1.7.x] Added Spatialite support to the new migration framework

Refs #22451.
Backport of 2ffa6ca7 from master.
parent 423e2cf1
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ 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
from django.contrib.gis.db.backends.spatialite.schema import SpatialiteSchemaEditor
from django.utils import six


@@ -37,6 +38,10 @@ class DatabaseWrapper(SQLiteDatabaseWrapper):
        self.creation = SpatiaLiteCreation(self)
        self.introspection = SpatiaLiteIntrospection(self)

    def schema_editor(self, *args, **kwargs):
        "Returns a new instance of this backend's SchemaEditor"
        return SpatialiteSchemaEditor(self, *args, **kwargs)

    def get_new_connection(self, conn_params):
        conn = super(DatabaseWrapper, self).get_new_connection(conn_params)
        # Enabling extension loading on the SQLite connection.
+97 −0
Original line number Diff line number Diff line
from django.db.backends.sqlite3.schema import DatabaseSchemaEditor


class SpatialiteSchemaEditor(DatabaseSchemaEditor):
    sql_add_geometry_column = "SELECT AddGeometryColumn(%(table)s, %(column)s, %(srid)s, %(geom_type)s, %(dim)s, %(null)s)"
    sql_add_spatial_index = "SELECT CreateSpatialIndex(%(table)s, %(column)s)"
    sql_drop_spatial_index = "DROP TABLE idx_%(table)s_%(column)s"
    sql_remove_geometry_metadata = "SELECT DiscardGeometryColumn(%(table)s, %(column)s)"
    sql_update_geometry_columns = "UPDATE geometry_columns SET f_table_name = %(new_table)s WHERE f_table_name = %(old_table)s"

    def __init__(self, *args, **kwargs):
        super(SpatialiteSchemaEditor, self).__init__(*args, **kwargs)
        self.geometry_sql = []

    def geo_quote_name(self, name):
        return self.connection.ops.geo_quote_name(name)

    def column_sql(self, model, field, include_default=False):
        from django.contrib.gis.db.models.fields import GeometryField
        if not isinstance(field, GeometryField):
            return super(SpatialiteSchemaEditor, self).column_sql(model, field, include_default)

        # Geometry columns are created by the `AddGeometryColumn` function
        self.geometry_sql.append(
            self.sql_add_geometry_column % {
                "table": self.geo_quote_name(model._meta.db_table),
                "column": self.geo_quote_name(field.column),
                "srid": field.srid,
                "geom_type": self.geo_quote_name(field.geom_type),
                "dim": field.dim,
                "null": int(not field.null),
            }
        )

        if field.spatial_index:
            self.geometry_sql.append(
                self.sql_add_spatial_index % {
                    "table": self.quote_name(model._meta.db_table),
                    "column": self.quote_name(field.column),
                }
            )
        return None, None

    def remove_geometry_metadata(self, model, field):
        self.execute(
            self.sql_remove_geometry_metadata % {
                "table": self.quote_name(model._meta.db_table),
                "column": self.quote_name(field.column),
            }
        )
        self.execute(
            self.sql_drop_spatial_index % {
                "table": model._meta.db_table,
                "column": field.column,
            }
        )

    def create_model(self, model):
        super(SpatialiteSchemaEditor, self).create_model(model)
        # Create geometry columns
        for sql in self.geometry_sql:
            self.execute(sql)
        self.geometry_sql = []

    def delete_model(self, model):
        from django.contrib.gis.db.models.fields import GeometryField
        # Drop spatial metadata (dropping the table does not automatically remove them)
        for field in model._meta.local_fields:
            if isinstance(field, GeometryField):
                self.remove_geometry_metadata(model, field)
        super(SpatialiteSchemaEditor, self).delete_model(model)

    def add_field(self, model, field):
        from django.contrib.gis.db.models.fields import GeometryField
        if isinstance(field, GeometryField):
            # Populate self.geometry_sql
            self.column_sql(model, field)
            for sql in self.geometry_sql:
                self.execute(sql)
            self.geometry_sql = []
        else:
            super(SpatialiteSchemaEditor, self).add_field(model, field)

    def remove_field(self, model, field):
        from django.contrib.gis.db.models.fields import GeometryField
        if isinstance(field, GeometryField):
            self.remove_geometry_metadata(model, field)
        super(SpatialiteSchemaEditor, self).remove_field(model, field)

    def alter_db_table(self, model, old_db_table, new_db_table):
        super(SpatialiteSchemaEditor, self).alter_db_table(model, old_db_table, new_db_table)
        self.execute(
            self.sql_update_geometry_columns % {
                "old_table": self.quote_name(old_db_table),
                "new_table": self.quote_name(new_db_table),
            }
        )