You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

schema.py 2.8KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import logging
  2. from django.contrib.gis.db.models.fields import GeometryField
  3. from django.db.backends.mysql.schema import DatabaseSchemaEditor
  4. from django.db.utils import OperationalError
  5. logger = logging.getLogger('django.contrib.gis')
  6. class MySQLGISSchemaEditor(DatabaseSchemaEditor):
  7. sql_add_spatial_index = 'CREATE SPATIAL INDEX %(index)s ON %(table)s(%(column)s)'
  8. sql_drop_spatial_index = 'DROP INDEX %(index)s ON %(table)s'
  9. def __init__(self, *args, **kwargs):
  10. super().__init__(*args, **kwargs)
  11. self.geometry_sql = []
  12. def skip_default(self, field):
  13. return (
  14. super().skip_default(field) or
  15. # Geometry fields are stored as BLOB/TEXT and can't have defaults.
  16. isinstance(field, GeometryField)
  17. )
  18. def column_sql(self, model, field, include_default=False):
  19. column_sql = super().column_sql(model, field, include_default)
  20. # MySQL doesn't support spatial indexes on NULL columns
  21. if isinstance(field, GeometryField) and field.spatial_index and not field.null:
  22. qn = self.connection.ops.quote_name
  23. db_table = model._meta.db_table
  24. self.geometry_sql.append(
  25. self.sql_add_spatial_index % {
  26. 'index': qn(self._create_spatial_index_name(model, field)),
  27. 'table': qn(db_table),
  28. 'column': qn(field.column),
  29. }
  30. )
  31. return column_sql
  32. def create_model(self, model):
  33. super().create_model(model)
  34. self.create_spatial_indexes()
  35. def add_field(self, model, field):
  36. super().add_field(model, field)
  37. self.create_spatial_indexes()
  38. def remove_field(self, model, field):
  39. if isinstance(field, GeometryField) and field.spatial_index:
  40. qn = self.connection.ops.quote_name
  41. sql = self.sql_drop_spatial_index % {
  42. 'index': qn(self._create_spatial_index_name(model, field)),
  43. 'table': qn(model._meta.db_table),
  44. }
  45. try:
  46. self.execute(sql)
  47. except OperationalError:
  48. logger.error(
  49. "Couldn't remove spatial index: %s (may be expected "
  50. "if your storage engine doesn't support them).", sql
  51. )
  52. super().remove_field(model, field)
  53. def _create_spatial_index_name(self, model, field):
  54. return '%s_%s_id' % (model._meta.db_table, field.column)
  55. def create_spatial_indexes(self):
  56. for sql in self.geometry_sql:
  57. try:
  58. self.execute(sql)
  59. except OperationalError:
  60. logger.error(
  61. "Cannot create SPATIAL INDEX %s. Only MyISAM and (as of "
  62. "MySQL 5.7.5) InnoDB support them.", sql
  63. )
  64. self.geometry_sql = []