Commit 3caf957e authored by Claude Paroz's avatar Claude Paroz
Browse files

Removed GeoWhereNode, obsoleted by GISLookup

parent b8fc167b
Loading
Loading
Loading
Loading
+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.
@@ -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
+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',
]
+5 −6
Original line number Diff line number Diff line
@@ -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

@@ -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 = {}
@@ -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)
+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