123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- from django.db.backends.sqlite3.schema import DatabaseSchemaEditor
- from django.db.utils import DatabaseError
-
-
- 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_recover_geometry_metadata = (
- "SELECT RecoverGeometryColumn(%(table)s, %(column)s, %(srid)s, "
- "%(geom_type)s, %(dim)s)"
- )
- sql_remove_geometry_metadata = "SELECT DiscardGeometryColumn(%(table)s, %(column)s)"
- sql_discard_geometry_columns = "DELETE FROM %(geom_table)s WHERE f_table_name = %(table)s"
- sql_update_geometry_columns = (
- "UPDATE %(geom_table)s SET f_table_name = %(new_table)s "
- "WHERE f_table_name = %(old_table)s"
- )
-
- geometry_tables = [
- "geometry_columns",
- "geometry_columns_auth",
- "geometry_columns_time",
- "geometry_columns_statistics",
- ]
-
- def __init__(self, *args, **kwargs):
- super().__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().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().create_model(model)
- # Create geometry columns
- for sql in self.geometry_sql:
- self.execute(sql)
- self.geometry_sql = []
-
- def delete_model(self, model, **kwargs):
- 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)
- # Make sure all geom stuff is gone
- for geom_table in self.geometry_tables:
- try:
- self.execute(
- self.sql_discard_geometry_columns % {
- "geom_table": geom_table,
- "table": self.quote_name(model._meta.db_table),
- }
- )
- except DatabaseError:
- pass
- super().delete_model(model, **kwargs)
-
- 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().add_field(model, field)
-
- def remove_field(self, model, field):
- from django.contrib.gis.db.models.fields import GeometryField
- # NOTE: If the field is a geometry field, the table is just recreated,
- # the parent's remove_field can't be used cause it will skip the
- # recreation if the field does not have a database type. Geometry fields
- # do not have a db type cause they are added and removed via stored
- # procedures.
- if isinstance(field, GeometryField):
- self._remake_table(model, delete_field=field)
- else:
- super().remove_field(model, field)
-
- def alter_db_table(self, model, old_db_table, new_db_table, disable_constraints=True):
- from django.contrib.gis.db.models.fields import GeometryField
- # Remove geometry-ness from temp table
- for field in model._meta.local_fields:
- if isinstance(field, GeometryField):
- self.execute(
- self.sql_remove_geometry_metadata % {
- "table": self.quote_name(old_db_table),
- "column": self.quote_name(field.column),
- }
- )
- # Alter table
- super().alter_db_table(model, old_db_table, new_db_table, disable_constraints)
- # Repoint any straggler names
- for geom_table in self.geometry_tables:
- try:
- self.execute(
- self.sql_update_geometry_columns % {
- "geom_table": geom_table,
- "old_table": self.quote_name(old_db_table),
- "new_table": self.quote_name(new_db_table),
- }
- )
- except DatabaseError:
- pass
- # Re-add geometry-ness and rename spatial index tables
- for field in model._meta.local_fields:
- if isinstance(field, GeometryField):
- self.execute(self.sql_recover_geometry_metadata % {
- "table": self.geo_quote_name(new_db_table),
- "column": self.geo_quote_name(field.column),
- "srid": field.srid,
- "geom_type": self.geo_quote_name(field.geom_type),
- "dim": field.dim,
- })
- if getattr(field, 'spatial_index', False):
- self.execute(self.sql_rename_table % {
- "old_table": self.quote_name("idx_%s_%s" % (old_db_table, field.column)),
- "new_table": self.quote_name("idx_%s_%s" % (new_db_table, field.column)),
- })
|