GIS lookup support added

This commit is contained in:
Anssi Kääriäinen 2013-12-01 21:02:16 +02:00
parent 760e28e72b
commit 074e0f5aca
8 changed files with 55 additions and 28 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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.

View File

@ -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']

View File

@ -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):

View File

@ -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

View File

@ -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.