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.

operations.py 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from django.contrib.gis.db.backends.base.adapter import WKTAdapter
  2. from django.contrib.gis.db.backends.base.operations import (
  3. BaseSpatialOperations,
  4. )
  5. from django.contrib.gis.db.backends.utils import SpatialOperator
  6. from django.contrib.gis.db.models import aggregates
  7. from django.contrib.gis.geos.geometry import GEOSGeometryBase
  8. from django.contrib.gis.geos.prototypes.io import wkb_r
  9. from django.contrib.gis.measure import Distance
  10. from django.db.backends.mysql.operations import DatabaseOperations
  11. from django.utils.functional import cached_property
  12. class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
  13. mysql = True
  14. name = 'mysql'
  15. geom_func_prefix = 'ST_'
  16. Adapter = WKTAdapter
  17. @cached_property
  18. def select(self):
  19. return self.geom_func_prefix + 'AsBinary(%s)'
  20. @cached_property
  21. def from_text(self):
  22. return self.geom_func_prefix + 'GeomFromText'
  23. @cached_property
  24. def gis_operators(self):
  25. MBREquals = 'MBREqual' if (
  26. self.connection.mysql_is_mariadb or self.connection.mysql_version < (5, 7, 6)
  27. ) else 'MBREquals'
  28. return {
  29. 'bbcontains': SpatialOperator(func='MBRContains'), # For consistency w/PostGIS API
  30. 'bboverlaps': SpatialOperator(func='MBROverlaps'), # ...
  31. 'contained': SpatialOperator(func='MBRWithin'), # ...
  32. 'contains': SpatialOperator(func='MBRContains'),
  33. 'disjoint': SpatialOperator(func='MBRDisjoint'),
  34. 'equals': SpatialOperator(func=MBREquals),
  35. 'exact': SpatialOperator(func=MBREquals),
  36. 'intersects': SpatialOperator(func='MBRIntersects'),
  37. 'overlaps': SpatialOperator(func='MBROverlaps'),
  38. 'same_as': SpatialOperator(func=MBREquals),
  39. 'touches': SpatialOperator(func='MBRTouches'),
  40. 'within': SpatialOperator(func='MBRWithin'),
  41. }
  42. disallowed_aggregates = (
  43. aggregates.Collect, aggregates.Extent, aggregates.Extent3D,
  44. aggregates.MakeLine, aggregates.Union,
  45. )
  46. @cached_property
  47. def unsupported_functions(self):
  48. unsupported = {
  49. 'AsGML', 'AsKML', 'AsSVG', 'Azimuth', 'BoundingCircle',
  50. 'ForcePolygonCW', 'ForceRHR', 'LineLocatePoint', 'MakeValid',
  51. 'MemSize', 'Perimeter', 'PointOnSurface', 'Reverse', 'Scale',
  52. 'SnapToGrid', 'Transform', 'Translate',
  53. }
  54. if self.connection.mysql_is_mariadb:
  55. unsupported.update({'GeoHash', 'IsValid'})
  56. if self.connection.mysql_version < (10, 2, 4):
  57. unsupported.add('AsGeoJSON')
  58. elif self.connection.mysql_version < (5, 7, 5):
  59. unsupported.update({'AsGeoJSON', 'GeoHash', 'IsValid'})
  60. return unsupported
  61. def geo_db_type(self, f):
  62. return f.geom_type
  63. def get_distance(self, f, value, lookup_type):
  64. value = value[0]
  65. if isinstance(value, Distance):
  66. if f.geodetic(self.connection):
  67. raise ValueError(
  68. 'Only numeric values of degree units are allowed on '
  69. 'geodetic distance queries.'
  70. )
  71. dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
  72. else:
  73. dist_param = value
  74. return [dist_param]
  75. def get_geometry_converter(self, expression):
  76. read = wkb_r().read
  77. srid = expression.output_field.srid
  78. if srid == -1:
  79. srid = None
  80. geom_class = expression.output_field.geom_class
  81. def converter(value, expression, connection):
  82. if value is not None:
  83. geom = GEOSGeometryBase(read(memoryview(value)), geom_class)
  84. if srid:
  85. geom.srid = srid
  86. return geom
  87. return converter