Loading django/contrib/gis/db/backends/mysql/base.py +5 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrappe from django.contrib.gis.db.backends.mysql.creation import MySQLCreation from django.contrib.gis.db.backends.mysql.introspection import MySQLIntrospection from django.contrib.gis.db.backends.mysql.operations import MySQLOperations from django.contrib.gis.db.backends.mysql.schema import MySQLGISSchemaEditor class DatabaseWrapper(MySQLDatabaseWrapper): Loading @@ -10,3 +11,7 @@ class DatabaseWrapper(MySQLDatabaseWrapper): self.creation = MySQLCreation(self) self.ops = MySQLOperations(self) self.introspection = MySQLIntrospection(self) def schema_editor(self, *args, **kwargs): "Returns a new instance of this backend's SchemaEditor" return MySQLGISSchemaEditor(self, *args, **kwargs) django/contrib/gis/db/backends/mysql/introspection.py +8 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,11 @@ class MySQLIntrospection(DatabaseIntrospection): cursor.close() return field_type, field_params def supports_spatial_index(self, cursor, table_name): # Supported with MyISAM, or InnoDB on MySQL 5.7.5+ storage_engine = self.get_storage_engine(cursor, table_name) return ( (storage_engine == 'InnoDB' and self.connection.mysql_version >= (5, 7, 5)) or storage_engine == 'MyISAM' ) django/contrib/gis/db/backends/mysql/schema.py 0 → 100644 +70 −0 Original line number Diff line number Diff line import logging from django.contrib.gis.db.models.fields import GeometryField from django.db.utils import OperationalError from django.db.backends.mysql.schema import DatabaseSchemaEditor logger = logging.getLogger('django.contrib.gis') class MySQLGISSchemaEditor(DatabaseSchemaEditor): sql_add_spatial_index = 'CREATE SPATIAL INDEX %(index)s ON %(table)s(%(column)s)' sql_drop_spatial_index = 'DROP INDEX %(index)s ON %(table)s' def __init__(self, *args, **kwargs): super(MySQLGISSchemaEditor, self).__init__(*args, **kwargs) self.geometry_sql = [] def column_sql(self, model, field, include_default=False): column_sql = super(MySQLGISSchemaEditor, self).column_sql(model, field, include_default) # MySQL doesn't support spatial indexes on NULL columns if isinstance(field, GeometryField) and field.spatial_index and not field.null: qn = self.connection.ops.quote_name db_table = model._meta.db_table self.geometry_sql.append( self.sql_add_spatial_index % { 'index': qn(self._create_spatial_index_name(model, field)), 'table': qn(db_table), 'column': qn(field.column), } ) return column_sql def create_model(self, model): super(MySQLGISSchemaEditor, self).create_model(model) self.create_spatial_indexes() def add_field(self, model, field): super(MySQLGISSchemaEditor, self).add_field(model, field) self.create_spatial_indexes() def remove_field(self, model, field): if isinstance(field, GeometryField) and field.spatial_index: qn = self.connection.ops.quote_name sql = self.sql_drop_spatial_index % { 'index': qn(self._create_spatial_index_name(model, field)), 'table': qn(model._meta.db_table), } try: self.execute(sql) except OperationalError: logger.error( "Couldn't remove spatial index: %s (may be expected " "if your storage engine doesn't support them)." % sql ) super(MySQLGISSchemaEditor, self).remove_field(model, field) def _create_spatial_index_name(self, model, field): return '%s_%s_id' % (model._meta.db_table, field.column) def create_spatial_indexes(self): for sql in self.geometry_sql: try: self.execute(sql) except OperationalError: logger.error( "Cannot create SPATIAL INDEX %s. Only MyISAM and (as of " "MySQL 5.7.5) InnoDB support them." % sql ) self.geometry_sql = [] django/contrib/gis/db/backends/spatialite/introspection.py +9 −0 Original line number Diff line number Diff line Loading @@ -53,3 +53,12 @@ class SpatiaLiteIntrospection(DatabaseIntrospection): cursor.close() return field_type, field_params def get_indexes(self, cursor, table_name): indexes = super(SpatiaLiteIntrospection, self).get_indexes(cursor, table_name) cursor.execute('SELECT f_geometry_column ' 'FROM geometry_columns ' 'WHERE f_table_name=%s AND spatial_index_enabled=1', (table_name,)) for row in cursor.fetchall(): indexes[row[0]] = {'primary_key': False, 'unique': False} return indexes django/contrib/gis/tests/gis_migrations/migrations/0001_initial.py +2 −2 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=100, unique=True)), ('geom', django.contrib.gis.db.models.fields.MultiPolygonField(srid=4326, null=True)), ('geom', django.contrib.gis.db.models.fields.MultiPolygonField(srid=4326)), ], options={ }, Loading @@ -25,7 +25,7 @@ class Migration(migrations.Migration): ('neighborhood', models.ForeignKey(to='gis.Neighborhood', to_field='id', null=True)), ('address', models.CharField(max_length=100)), ('zip_code', models.IntegerField(null=True, blank=True)), ('geom', django.contrib.gis.db.models.fields.PointField(srid=4326, null=True, geography=True)), ('geom', django.contrib.gis.db.models.fields.PointField(srid=4326, geography=True)), ], options={ }, Loading Loading
django/contrib/gis/db/backends/mysql/base.py +5 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrappe from django.contrib.gis.db.backends.mysql.creation import MySQLCreation from django.contrib.gis.db.backends.mysql.introspection import MySQLIntrospection from django.contrib.gis.db.backends.mysql.operations import MySQLOperations from django.contrib.gis.db.backends.mysql.schema import MySQLGISSchemaEditor class DatabaseWrapper(MySQLDatabaseWrapper): Loading @@ -10,3 +11,7 @@ class DatabaseWrapper(MySQLDatabaseWrapper): self.creation = MySQLCreation(self) self.ops = MySQLOperations(self) self.introspection = MySQLIntrospection(self) def schema_editor(self, *args, **kwargs): "Returns a new instance of this backend's SchemaEditor" return MySQLGISSchemaEditor(self, *args, **kwargs)
django/contrib/gis/db/backends/mysql/introspection.py +8 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,11 @@ class MySQLIntrospection(DatabaseIntrospection): cursor.close() return field_type, field_params def supports_spatial_index(self, cursor, table_name): # Supported with MyISAM, or InnoDB on MySQL 5.7.5+ storage_engine = self.get_storage_engine(cursor, table_name) return ( (storage_engine == 'InnoDB' and self.connection.mysql_version >= (5, 7, 5)) or storage_engine == 'MyISAM' )
django/contrib/gis/db/backends/mysql/schema.py 0 → 100644 +70 −0 Original line number Diff line number Diff line import logging from django.contrib.gis.db.models.fields import GeometryField from django.db.utils import OperationalError from django.db.backends.mysql.schema import DatabaseSchemaEditor logger = logging.getLogger('django.contrib.gis') class MySQLGISSchemaEditor(DatabaseSchemaEditor): sql_add_spatial_index = 'CREATE SPATIAL INDEX %(index)s ON %(table)s(%(column)s)' sql_drop_spatial_index = 'DROP INDEX %(index)s ON %(table)s' def __init__(self, *args, **kwargs): super(MySQLGISSchemaEditor, self).__init__(*args, **kwargs) self.geometry_sql = [] def column_sql(self, model, field, include_default=False): column_sql = super(MySQLGISSchemaEditor, self).column_sql(model, field, include_default) # MySQL doesn't support spatial indexes on NULL columns if isinstance(field, GeometryField) and field.spatial_index and not field.null: qn = self.connection.ops.quote_name db_table = model._meta.db_table self.geometry_sql.append( self.sql_add_spatial_index % { 'index': qn(self._create_spatial_index_name(model, field)), 'table': qn(db_table), 'column': qn(field.column), } ) return column_sql def create_model(self, model): super(MySQLGISSchemaEditor, self).create_model(model) self.create_spatial_indexes() def add_field(self, model, field): super(MySQLGISSchemaEditor, self).add_field(model, field) self.create_spatial_indexes() def remove_field(self, model, field): if isinstance(field, GeometryField) and field.spatial_index: qn = self.connection.ops.quote_name sql = self.sql_drop_spatial_index % { 'index': qn(self._create_spatial_index_name(model, field)), 'table': qn(model._meta.db_table), } try: self.execute(sql) except OperationalError: logger.error( "Couldn't remove spatial index: %s (may be expected " "if your storage engine doesn't support them)." % sql ) super(MySQLGISSchemaEditor, self).remove_field(model, field) def _create_spatial_index_name(self, model, field): return '%s_%s_id' % (model._meta.db_table, field.column) def create_spatial_indexes(self): for sql in self.geometry_sql: try: self.execute(sql) except OperationalError: logger.error( "Cannot create SPATIAL INDEX %s. Only MyISAM and (as of " "MySQL 5.7.5) InnoDB support them." % sql ) self.geometry_sql = []
django/contrib/gis/db/backends/spatialite/introspection.py +9 −0 Original line number Diff line number Diff line Loading @@ -53,3 +53,12 @@ class SpatiaLiteIntrospection(DatabaseIntrospection): cursor.close() return field_type, field_params def get_indexes(self, cursor, table_name): indexes = super(SpatiaLiteIntrospection, self).get_indexes(cursor, table_name) cursor.execute('SELECT f_geometry_column ' 'FROM geometry_columns ' 'WHERE f_table_name=%s AND spatial_index_enabled=1', (table_name,)) for row in cursor.fetchall(): indexes[row[0]] = {'primary_key': False, 'unique': False} return indexes
django/contrib/gis/tests/gis_migrations/migrations/0001_initial.py +2 −2 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=100, unique=True)), ('geom', django.contrib.gis.db.models.fields.MultiPolygonField(srid=4326, null=True)), ('geom', django.contrib.gis.db.models.fields.MultiPolygonField(srid=4326)), ], options={ }, Loading @@ -25,7 +25,7 @@ class Migration(migrations.Migration): ('neighborhood', models.ForeignKey(to='gis.Neighborhood', to_field='id', null=True)), ('address', models.CharField(max_length=100)), ('zip_code', models.IntegerField(null=True, blank=True)), ('geom', django.contrib.gis.db.models.fields.PointField(srid=4326, null=True, geography=True)), ('geom', django.contrib.gis.db.models.fields.PointField(srid=4326, geography=True)), ], options={ }, Loading