GIS lookup support added
This commit is contained in:
parent
760e28e72b
commit
074e0f5aca
|
@ -49,9 +49,7 @@ class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
return placeholder
|
return placeholder
|
||||||
|
|
||||||
def spatial_lookup_sql(self, lvalue, lookup_type, value, field, qn):
|
def spatial_lookup_sql(self, lvalue, lookup_type, value, field, qn):
|
||||||
alias, col, db_type = lvalue
|
geo_col, db_type = lvalue
|
||||||
|
|
||||||
geo_col = '%s.%s' % (qn(alias), qn(col))
|
|
||||||
|
|
||||||
lookup_info = self.geometry_functions.get(lookup_type, False)
|
lookup_info = self.geometry_functions.get(lookup_type, False)
|
||||||
if lookup_info:
|
if lookup_info:
|
||||||
|
|
|
@ -231,10 +231,7 @@ class OracleOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
|
|
||||||
def spatial_lookup_sql(self, lvalue, lookup_type, value, field, qn):
|
def spatial_lookup_sql(self, lvalue, lookup_type, value, field, qn):
|
||||||
"Returns the SQL WHERE clause for use in Oracle spatial SQL construction."
|
"Returns the SQL WHERE clause for use in Oracle spatial SQL construction."
|
||||||
alias, col, db_type = lvalue
|
geo_col, db_type = lvalue
|
||||||
|
|
||||||
# Getting the quoted table name as `geo_col`.
|
|
||||||
geo_col = '%s.%s' % (qn(alias), qn(col))
|
|
||||||
|
|
||||||
# See if a Oracle Geometry function matches the lookup type next
|
# See if a Oracle Geometry function matches the lookup type next
|
||||||
lookup_info = self.geometry_functions.get(lookup_type, False)
|
lookup_info = self.geometry_functions.get(lookup_type, False)
|
||||||
|
|
|
@ -478,10 +478,7 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
(alias, col, db_type), the lookup type string, lookup value, and
|
(alias, col, db_type), the lookup type string, lookup value, and
|
||||||
the geometry field.
|
the geometry field.
|
||||||
"""
|
"""
|
||||||
alias, col, db_type = lvalue
|
geo_col, db_type = lvalue
|
||||||
|
|
||||||
# Getting the quoted geometry column.
|
|
||||||
geo_col = '%s.%s' % (qn(alias), qn(col))
|
|
||||||
|
|
||||||
if lookup_type in self.geometry_operators:
|
if lookup_type in self.geometry_operators:
|
||||||
if field.geography and not lookup_type in self.geography_operators:
|
if field.geography and not lookup_type in self.geography_operators:
|
||||||
|
|
|
@ -324,10 +324,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
[a tuple of (alias, column, db_type)], lookup type, lookup
|
[a tuple of (alias, column, db_type)], lookup type, lookup
|
||||||
value, the model field, and the quoting function.
|
value, the model field, and the quoting function.
|
||||||
"""
|
"""
|
||||||
alias, col, db_type = lvalue
|
geo_col, db_type = lvalue
|
||||||
|
|
||||||
# Getting the quoted field as `geo_col`.
|
|
||||||
geo_col = '%s.%s' % (qn(alias), qn(col))
|
|
||||||
|
|
||||||
if lookup_type in self.geometry_functions:
|
if lookup_type in self.geometry_functions:
|
||||||
# See if a SpatiaLite geometry function matches the lookup type.
|
# See if a SpatiaLite geometry function matches the lookup type.
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
from django.db.models.sql.constants import QUERY_TERMS
|
||||||
|
|
||||||
|
ALL_TERMS = set([
|
||||||
|
'bbcontains', 'bboverlaps', 'contained', 'contains',
|
||||||
|
'contains_properly', 'coveredby', 'covers', 'crosses', 'disjoint',
|
||||||
|
'distance_gt', 'distance_gte', 'distance_lt', 'distance_lte',
|
||||||
|
'dwithin', 'equals', 'exact',
|
||||||
|
'intersects', 'overlaps', 'relate', 'same_as', 'touches', 'within',
|
||||||
|
'left', 'right', 'overlaps_left', 'overlaps_right',
|
||||||
|
'overlaps_above', 'overlaps_below',
|
||||||
|
'strictly_above', 'strictly_below'
|
||||||
|
])
|
||||||
|
GIS_LOOKUPS = ALL_TERMS.copy()
|
||||||
|
ALL_TERMS.update(QUERY_TERMS)
|
||||||
|
|
||||||
|
__all__ = ['ALL_TERMS', 'GIS_LOOKUPS']
|
|
@ -2,6 +2,8 @@ from django.db.models.fields import Field
|
||||||
from django.db.models.sql.expressions import SQLEvaluator
|
from django.db.models.sql.expressions import SQLEvaluator
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.contrib.gis import forms
|
from django.contrib.gis import forms
|
||||||
|
from django.contrib.gis.db.models.constants import GIS_LOOKUPS
|
||||||
|
from django.contrib.gis.db.models.lookups import GISLookup
|
||||||
from django.contrib.gis.db.models.proxy import GeometryProxy
|
from django.contrib.gis.db.models.proxy import GeometryProxy
|
||||||
from django.contrib.gis.geometry.backend import Geometry, GeometryException
|
from django.contrib.gis.geometry.backend import Geometry, GeometryException
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -284,6 +286,10 @@ class GeometryField(Field):
|
||||||
"""
|
"""
|
||||||
return connection.ops.get_geom_placeholder(self, value)
|
return connection.ops.get_geom_placeholder(self, value)
|
||||||
|
|
||||||
|
for lookup_name in GIS_LOOKUPS:
|
||||||
|
lookup = type(lookup_name, (GISLookup,), {'lookup_name': lookup_name})
|
||||||
|
GeometryField.register_lookup(lookup)
|
||||||
|
|
||||||
|
|
||||||
# The OpenGIS Geometry Type Fields
|
# The OpenGIS Geometry Type Fields
|
||||||
class PointField(GeometryField):
|
class PointField(GeometryField):
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
from django.db.models.lookups import Lookup
|
||||||
|
from django.db.models.sql.expressions import SQLEvaluator
|
||||||
|
|
||||||
|
|
||||||
|
class GISLookup(Lookup):
|
||||||
|
def as_sql(self, qn, connection):
|
||||||
|
from django.contrib.gis.db.models.sql import GeoWhereNode
|
||||||
|
# We use the same approach as was used by GeoWhereNode. It would
|
||||||
|
# be a good idea to upgrade GIS to use similar code that is used
|
||||||
|
# for other lookups.
|
||||||
|
if isinstance(self.rhs, SQLEvaluator):
|
||||||
|
# Make sure the F Expression destination field exists, and
|
||||||
|
# set an `srid` attribute with the same as that of the
|
||||||
|
# destination.
|
||||||
|
geo_fld = GeoWhereNode._check_geo_field(self.rhs.opts, self.rhs.expression.name)
|
||||||
|
if not geo_fld:
|
||||||
|
raise ValueError('No geographic field found in expression.')
|
||||||
|
self.rhs.srid = geo_fld.srid
|
||||||
|
db_type = self.lhs.output_type.db_type(connection=connection)
|
||||||
|
params = self.lhs.output_type.get_db_prep_lookup(
|
||||||
|
self.lookup_name, self.rhs, connection=connection)
|
||||||
|
lhs_sql, lhs_params = self.process_lhs(qn, connection)
|
||||||
|
# lhs_params not currently supported.
|
||||||
|
assert not lhs_params
|
||||||
|
data = (lhs_sql, db_type)
|
||||||
|
spatial_sql, spatial_params = connection.ops.spatial_lookup_sql(
|
||||||
|
data, self.lookup_name, self.rhs, self.lhs.output_type, qn)
|
||||||
|
return spatial_sql, spatial_params + params
|
|
@ -1,6 +1,7 @@
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
from django.db.models.query import sql
|
from django.db.models.query import sql
|
||||||
|
|
||||||
|
from django.contrib.gis.db.models.constants import ALL_TERMS
|
||||||
from django.contrib.gis.db.models.fields import GeometryField
|
from django.contrib.gis.db.models.fields import GeometryField
|
||||||
from django.contrib.gis.db.models.sql import aggregates as gis_aggregates
|
from django.contrib.gis.db.models.sql import aggregates as gis_aggregates
|
||||||
from django.contrib.gis.db.models.sql.conversion import AreaField, DistanceField, GeomField
|
from django.contrib.gis.db.models.sql.conversion import AreaField, DistanceField, GeomField
|
||||||
|
@ -9,19 +10,6 @@ from django.contrib.gis.geometry.backend import Geometry
|
||||||
from django.contrib.gis.measure import Area, Distance
|
from django.contrib.gis.measure import Area, Distance
|
||||||
|
|
||||||
|
|
||||||
ALL_TERMS = set([
|
|
||||||
'bbcontains', 'bboverlaps', 'contained', 'contains',
|
|
||||||
'contains_properly', 'coveredby', 'covers', 'crosses', 'disjoint',
|
|
||||||
'distance_gt', 'distance_gte', 'distance_lt', 'distance_lte',
|
|
||||||
'dwithin', 'equals', 'exact',
|
|
||||||
'intersects', 'overlaps', 'relate', 'same_as', 'touches', 'within',
|
|
||||||
'left', 'right', 'overlaps_left', 'overlaps_right',
|
|
||||||
'overlaps_above', 'overlaps_below',
|
|
||||||
'strictly_above', 'strictly_below'
|
|
||||||
])
|
|
||||||
ALL_TERMS.update(sql.constants.QUERY_TERMS)
|
|
||||||
|
|
||||||
|
|
||||||
class GeoQuery(sql.Query):
|
class GeoQuery(sql.Query):
|
||||||
"""
|
"""
|
||||||
A single spatial SQL query.
|
A single spatial SQL query.
|
||||||
|
|
Loading…
Reference in New Issue