Complete rework of translating data values from database Deprecation of SubfieldBase, removal of resolve_columns and convert_values in favour of a more general converter based approach and public API Field.from_db_value(). Now works seamlessly with aggregation, .values() and raw queries. Thanks to akaariai in particular for extensive advice and inspiration, also to shaib, manfre and timograham for their reviews.
66 lines
2.3 KiB
Python
66 lines
2.3 KiB
Python
from django.db.backends.mysql.base import DatabaseOperations
|
|
|
|
from django.contrib.gis.db.backends.adapter import WKTAdapter
|
|
from django.contrib.gis.db.backends.base import BaseSpatialOperations
|
|
|
|
|
|
class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
|
|
|
|
compiler_module = 'django.contrib.gis.db.models.sql.compiler'
|
|
mysql = True
|
|
name = 'mysql'
|
|
select = 'AsText(%s)'
|
|
from_wkb = 'GeomFromWKB'
|
|
from_text = 'GeomFromText'
|
|
|
|
Adapter = WKTAdapter
|
|
Adaptor = Adapter # Backwards-compatibility alias.
|
|
|
|
geometry_functions = {
|
|
'bbcontains': 'MBRContains', # For consistency w/PostGIS API
|
|
'bboverlaps': 'MBROverlaps', # .. ..
|
|
'contained': 'MBRWithin', # .. ..
|
|
'contains': 'MBRContains',
|
|
'disjoint': 'MBRDisjoint',
|
|
'equals': 'MBREqual',
|
|
'exact': 'MBREqual',
|
|
'intersects': 'MBRIntersects',
|
|
'overlaps': 'MBROverlaps',
|
|
'same_as': 'MBREqual',
|
|
'touches': 'MBRTouches',
|
|
'within': 'MBRWithin',
|
|
}
|
|
|
|
gis_terms = set(geometry_functions) | set(['isnull'])
|
|
|
|
def geo_db_type(self, f):
|
|
return f.geom_type
|
|
|
|
def get_geom_placeholder(self, value, srid):
|
|
"""
|
|
The placeholder here has to include MySQL's WKT constructor. Because
|
|
MySQL does not support spatial transformations, there is no need to
|
|
modify the placeholder based on the contents of the given value.
|
|
"""
|
|
if hasattr(value, 'expression'):
|
|
placeholder = self.get_expression_column(value)
|
|
else:
|
|
placeholder = '%s(%%s)' % self.from_text
|
|
return placeholder
|
|
|
|
def spatial_lookup_sql(self, lvalue, lookup_type, value, field, qn):
|
|
geo_col, db_type = lvalue
|
|
|
|
lookup_info = self.geometry_functions.get(lookup_type, False)
|
|
if lookup_info:
|
|
sql = "%s(%s, %s)" % (lookup_info, geo_col,
|
|
self.get_geom_placeholder(value, field.srid))
|
|
return sql, []
|
|
|
|
# TODO: Is this really necessary? MySQL can't handle NULL geometries
|
|
# in its spatial indexes anyways.
|
|
if lookup_type == 'isnull':
|
|
return "%s IS %sNULL" % (geo_col, ('' if value else 'NOT ')), []
|
|
|
|
raise TypeError("Got invalid lookup_type: %s" % repr(lookup_type))
|