Loading django/contrib/gis/db/models/lookups.py +43 −2 Original line number Diff line number Diff line from django.db.models.constants import LOOKUP_SEP from django.db.models.fields import FieldDoesNotExist from django.db.models.lookups import Lookup from django.db.models.sql.expressions import SQLEvaluator class GISLookup(Lookup): @classmethod def _check_geo_field(cls, opts, lookup): """ Utility for checking the given lookup with the given model options. The lookup is a string either specifying the geographic field, e.g. 'point, 'the_geom', or a related lookup on a geographic field like 'address__point'. If a GeometryField exists according to the given lookup on the model options, it will be returned. Otherwise returns None. """ from django.contrib.gis.db.models.fields import GeometryField # This takes into account the situation where the lookup is a # lookup to a related geographic field, e.g., 'address__point'. field_list = lookup.split(LOOKUP_SEP) # Reversing so list operates like a queue of related lookups, # and popping the top lookup. field_list.reverse() fld_name = field_list.pop() try: geo_fld = opts.get_field(fld_name) # If the field list is still around, then it means that the # lookup was for a geometry field across a relationship -- # thus we keep on getting the related model options and the # model field associated with the next field in the list # until there's no more left. while len(field_list): opts = geo_fld.rel.to._meta geo_fld = opts.get_field(field_list.pop()) except (FieldDoesNotExist, AttributeError): return False # Finally, make sure we got a Geographic field and return. if isinstance(geo_fld, GeometryField): return geo_fld else: return False 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. Loading @@ -12,7 +53,7 @@ class GISLookup(Lookup): # 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) geo_fld = self._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 Loading django/contrib/gis/db/models/sql/__init__.py +1 −2 Original line number Diff line number Diff line from django.contrib.gis.db.models.sql.conversion import AreaField, DistanceField, GeomField from django.contrib.gis.db.models.sql.query import GeoQuery from django.contrib.gis.db.models.sql.where import GeoWhereNode __all__ = [ 'AreaField', 'DistanceField', 'GeomField', 'GeoQuery', 'GeoWhereNode', 'AreaField', 'DistanceField', 'GeomField', 'GeoQuery', ] django/contrib/gis/db/models/sql/query.py +5 −6 Original line number Diff line number Diff line Loading @@ -3,9 +3,9 @@ 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.lookups import GISLookup 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.where import GeoWhereNode from django.contrib.gis.geometry.backend import Geometry from django.contrib.gis.measure import Area, Distance Loading @@ -21,11 +21,10 @@ class GeoQuery(sql.Query): compiler = 'GeoSQLCompiler' #### Methods overridden from the base Query class #### def __init__(self, model, where=GeoWhereNode): super(GeoQuery, self).__init__(model, where) def __init__(self, model): super(GeoQuery, self).__init__(model) #, where) # The following attributes are customized for the GeoQuerySet. # The GeoWhereNode and SpatialBackend classes contain backend-specific # routines and functions. # The SpatialBackend classes contain backend-specific routines and functions. self.custom_select = {} self.transformed_srid = None self.extra_select_fields = {} Loading Loading @@ -108,4 +107,4 @@ class GeoQuery(sql.Query): else: # Otherwise, check by the given field name -- which may be # a lookup to a _related_ geographic field. return GeoWhereNode._check_geo_field(self.model._meta, field_name) return GISLookup._check_geo_field(self.model._meta, field_name) django/contrib/gis/db/models/sql/where.pydeleted 100644 → 0 +0 −93 Original line number Diff line number Diff line from django.db.models.constants import LOOKUP_SEP from django.db.models.fields import FieldDoesNotExist from django.db.models.sql.expressions import SQLEvaluator from django.db.models.sql.where import Constraint, WhereNode from django.contrib.gis.db.models.fields import GeometryField class GeoConstraint(Constraint): """ This subclass overrides `process` to better handle geographic SQL construction. """ def __init__(self, init_constraint): self.alias = init_constraint.alias self.col = init_constraint.col self.field = init_constraint.field def process(self, lookup_type, value, connection): if isinstance(value, 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(value.opts, value.expression.name) if not geo_fld: raise ValueError('No geographic field found in expression.') value.srid = geo_fld.srid db_type = self.field.db_type(connection=connection) params = self.field.get_db_prep_lookup(lookup_type, value, connection=connection) return (self.alias, self.col, db_type), params class GeoWhereNode(WhereNode): """ Used to represent the SQL where-clause for spatial databases -- these are tied to the GeoQuery class that created it. """ def _prepare_data(self, data): if isinstance(data, (list, tuple)): obj, lookup_type, value = data if (isinstance(obj, Constraint) and isinstance(obj.field, GeometryField)): data = (GeoConstraint(obj), lookup_type, value) return super(GeoWhereNode, self)._prepare_data(data) def make_atom(self, child, qn, connection): lvalue, lookup_type, value_annot, params_or_value = child if isinstance(lvalue, GeoConstraint): data, params = lvalue.process(lookup_type, params_or_value, connection) spatial_sql, spatial_params = connection.ops.spatial_lookup_sql( data, lookup_type, params_or_value, lvalue.field, qn) return spatial_sql, spatial_params + params else: return super(GeoWhereNode, self).make_atom(child, qn, connection) @classmethod def _check_geo_field(cls, opts, lookup): """ Utility for checking the given lookup with the given model options. The lookup is a string either specifying the geographic field, e.g. 'point, 'the_geom', or a related lookup on a geographic field like 'address__point'. If a GeometryField exists according to the given lookup on the model options, it will be returned. Otherwise returns None. """ # This takes into account the situation where the lookup is a # lookup to a related geographic field, e.g., 'address__point'. field_list = lookup.split(LOOKUP_SEP) # Reversing so list operates like a queue of related lookups, # and popping the top lookup. field_list.reverse() fld_name = field_list.pop() try: geo_fld = opts.get_field(fld_name) # If the field list is still around, then it means that the # lookup was for a geometry field across a relationship -- # thus we keep on getting the related model options and the # model field associated with the next field in the list # until there's no more left. while len(field_list): opts = geo_fld.rel.to._meta geo_fld = opts.get_field(field_list.pop()) except (FieldDoesNotExist, AttributeError): return False # Finally, make sure we got a Geographic field and return. if isinstance(geo_fld, GeometryField): return geo_fld else: return False Loading
django/contrib/gis/db/models/lookups.py +43 −2 Original line number Diff line number Diff line from django.db.models.constants import LOOKUP_SEP from django.db.models.fields import FieldDoesNotExist from django.db.models.lookups import Lookup from django.db.models.sql.expressions import SQLEvaluator class GISLookup(Lookup): @classmethod def _check_geo_field(cls, opts, lookup): """ Utility for checking the given lookup with the given model options. The lookup is a string either specifying the geographic field, e.g. 'point, 'the_geom', or a related lookup on a geographic field like 'address__point'. If a GeometryField exists according to the given lookup on the model options, it will be returned. Otherwise returns None. """ from django.contrib.gis.db.models.fields import GeometryField # This takes into account the situation where the lookup is a # lookup to a related geographic field, e.g., 'address__point'. field_list = lookup.split(LOOKUP_SEP) # Reversing so list operates like a queue of related lookups, # and popping the top lookup. field_list.reverse() fld_name = field_list.pop() try: geo_fld = opts.get_field(fld_name) # If the field list is still around, then it means that the # lookup was for a geometry field across a relationship -- # thus we keep on getting the related model options and the # model field associated with the next field in the list # until there's no more left. while len(field_list): opts = geo_fld.rel.to._meta geo_fld = opts.get_field(field_list.pop()) except (FieldDoesNotExist, AttributeError): return False # Finally, make sure we got a Geographic field and return. if isinstance(geo_fld, GeometryField): return geo_fld else: return False 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. Loading @@ -12,7 +53,7 @@ class GISLookup(Lookup): # 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) geo_fld = self._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 Loading
django/contrib/gis/db/models/sql/__init__.py +1 −2 Original line number Diff line number Diff line from django.contrib.gis.db.models.sql.conversion import AreaField, DistanceField, GeomField from django.contrib.gis.db.models.sql.query import GeoQuery from django.contrib.gis.db.models.sql.where import GeoWhereNode __all__ = [ 'AreaField', 'DistanceField', 'GeomField', 'GeoQuery', 'GeoWhereNode', 'AreaField', 'DistanceField', 'GeomField', 'GeoQuery', ]
django/contrib/gis/db/models/sql/query.py +5 −6 Original line number Diff line number Diff line Loading @@ -3,9 +3,9 @@ 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.lookups import GISLookup 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.where import GeoWhereNode from django.contrib.gis.geometry.backend import Geometry from django.contrib.gis.measure import Area, Distance Loading @@ -21,11 +21,10 @@ class GeoQuery(sql.Query): compiler = 'GeoSQLCompiler' #### Methods overridden from the base Query class #### def __init__(self, model, where=GeoWhereNode): super(GeoQuery, self).__init__(model, where) def __init__(self, model): super(GeoQuery, self).__init__(model) #, where) # The following attributes are customized for the GeoQuerySet. # The GeoWhereNode and SpatialBackend classes contain backend-specific # routines and functions. # The SpatialBackend classes contain backend-specific routines and functions. self.custom_select = {} self.transformed_srid = None self.extra_select_fields = {} Loading Loading @@ -108,4 +107,4 @@ class GeoQuery(sql.Query): else: # Otherwise, check by the given field name -- which may be # a lookup to a _related_ geographic field. return GeoWhereNode._check_geo_field(self.model._meta, field_name) return GISLookup._check_geo_field(self.model._meta, field_name)
django/contrib/gis/db/models/sql/where.pydeleted 100644 → 0 +0 −93 Original line number Diff line number Diff line from django.db.models.constants import LOOKUP_SEP from django.db.models.fields import FieldDoesNotExist from django.db.models.sql.expressions import SQLEvaluator from django.db.models.sql.where import Constraint, WhereNode from django.contrib.gis.db.models.fields import GeometryField class GeoConstraint(Constraint): """ This subclass overrides `process` to better handle geographic SQL construction. """ def __init__(self, init_constraint): self.alias = init_constraint.alias self.col = init_constraint.col self.field = init_constraint.field def process(self, lookup_type, value, connection): if isinstance(value, 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(value.opts, value.expression.name) if not geo_fld: raise ValueError('No geographic field found in expression.') value.srid = geo_fld.srid db_type = self.field.db_type(connection=connection) params = self.field.get_db_prep_lookup(lookup_type, value, connection=connection) return (self.alias, self.col, db_type), params class GeoWhereNode(WhereNode): """ Used to represent the SQL where-clause for spatial databases -- these are tied to the GeoQuery class that created it. """ def _prepare_data(self, data): if isinstance(data, (list, tuple)): obj, lookup_type, value = data if (isinstance(obj, Constraint) and isinstance(obj.field, GeometryField)): data = (GeoConstraint(obj), lookup_type, value) return super(GeoWhereNode, self)._prepare_data(data) def make_atom(self, child, qn, connection): lvalue, lookup_type, value_annot, params_or_value = child if isinstance(lvalue, GeoConstraint): data, params = lvalue.process(lookup_type, params_or_value, connection) spatial_sql, spatial_params = connection.ops.spatial_lookup_sql( data, lookup_type, params_or_value, lvalue.field, qn) return spatial_sql, spatial_params + params else: return super(GeoWhereNode, self).make_atom(child, qn, connection) @classmethod def _check_geo_field(cls, opts, lookup): """ Utility for checking the given lookup with the given model options. The lookup is a string either specifying the geographic field, e.g. 'point, 'the_geom', or a related lookup on a geographic field like 'address__point'. If a GeometryField exists according to the given lookup on the model options, it will be returned. Otherwise returns None. """ # This takes into account the situation where the lookup is a # lookup to a related geographic field, e.g., 'address__point'. field_list = lookup.split(LOOKUP_SEP) # Reversing so list operates like a queue of related lookups, # and popping the top lookup. field_list.reverse() fld_name = field_list.pop() try: geo_fld = opts.get_field(fld_name) # If the field list is still around, then it means that the # lookup was for a geometry field across a relationship -- # thus we keep on getting the related model options and the # model field associated with the next field in the list # until there's no more left. while len(field_list): opts = geo_fld.rel.to._meta geo_fld = opts.get_field(field_list.pop()) except (FieldDoesNotExist, AttributeError): return False # Finally, make sure we got a Geographic field and return. if isinstance(geo_fld, GeometryField): return geo_fld else: return False