Exemplo n.º 1
0
    def get_distance(self, f, dist_val, lookup_type):
        """
        Retrieve the distance parameters for the given geometry field,
        distance lookup value, and the distance lookup type.

        This is the most complex implementation of the spatial backends due to
        what is supported on geodetic geometry columns vs. what's available on
        projected geometry columns.  In addition, it has to take into account
        the geography column type.
        """
        # Getting the distance parameter
        value = dist_val[0]

        # Shorthand boolean flags.
        geodetic = f.geodetic(self.connection)
        geography = f.geography

        if isinstance(value, Distance):
            if geography:
                dist_param = value.m
            elif geodetic:
                if lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are '
                                     'allowed on geographic DWithin queries.')
                dist_param = value.m
            else:
                dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = value

        return [dist_param]
Exemplo n.º 2
0
    def get_distance(self, f, value, lookup_type):
        """
        Returns the distance parameters given the value and the lookup type.
        On Oracle, geometry columns with a geodetic coordinate system behave
        implicitly like a geography column, and thus meters will be used as
        the distance parameter on them.
        """
        if not value:
            return []
        value = value[0]
        if isinstance(value, Distance):
            if f.geodetic(self.connection):
                dist_param = value.m
            else:
                dist_param = getattr(
                    value,
                    Distance.unit_attname(f.units_name(self.connection)))
        else:
            dist_param = value

        # dwithin lookups on Oracle require a special string parameter
        # that starts with "distance=".
        if lookup_type == 'dwithin':
            dist_param = 'distance=%s' % dist_param

        return [dist_param]
Exemplo n.º 3
0
    def get_distance(self, value, lookup_type, connection):
        """
        Returns a distance number in units of the field.  For example, if
        `D(km=1)` was passed in and the units of the field were in meters,
        then 1000 would be returned.
        """
        return connection.ops.get_distance(self, value, lookup_type)

        if isinstance(dist, Distance):
            if self.geodetic(connection):
                # Won't allow Distance objects w/DWithin lookups on PostGIS.
                if connection.ops.postgis and lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are allowed on geographic DWithin queries.')

                # Spherical distance calculation parameter should be in meters.
                dist_param = dist.m
            else:
                dist_param = getattr(dist, Distance.unit_attname(self.units_name(connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = dist

        if connection.ops.oracle and lookup_type == 'dwithin':
            dist_param = 'distance=%s' % dist_param

        if connection.ops.postgis and self.geodetic(connection) and lookup_type != 'dwithin' and option == 'spheroid':
            # On PostGIS, by default `ST_distance_sphere` is used; but if the
            # accuracy of `ST_distance_spheroid` is needed than the spheroid
            # needs to be passed to the SQL stored procedure.
            return [self._spheroid, dist_param]
        else:
            return [dist_param]
Exemplo n.º 4
0
    def get_distance(self, f, dist_val, lookup_type):
        """
        Retrieve the distance parameters for the given geometry field,
        distance lookup value, and the distance lookup type.

        This is the most complex implementation of the spatial backends due to
        what is supported on geodetic geometry columns vs. what's available on
        projected geometry columns.  In addition, it has to take into account
        the geography column type.
        """
        # Getting the distance parameter
        value = dist_val[0]

        # Shorthand boolean flags.
        geodetic = f.geodetic(self.connection)
        geography = f.geography

        if isinstance(value, Distance):
            if geography:
                dist_param = value.m
            elif geodetic:
                if lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are '
                                     'allowed on geographic DWithin queries.')
                dist_param = value.m
            else:
                dist_param = getattr(
                    value,
                    Distance.unit_attname(f.units_name(self.connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = value

        return [dist_param]
Exemplo n.º 5
0
    def get_distance(self, dist_val, lookup_type):
        """
        Returns a distance number in units of the field.  For example, if
        `D(km=1)` was passed in and the units of the field were in meters,
        then 1000 would be returned.
        """
        # Getting the distance parameter and any options.
        if len(dist_val) == 1: dist, option = dist_val[0], None
        else: dist, option = dist_val

        if isinstance(dist, Distance):
            if self.geodetic:
                # Won't allow Distance objects w/DWithin lookups on PostGIS.
                if SpatialBackend.postgis and lookup_type == 'dwithin':
                    raise TypeError('Only numeric values of degree units are allowed on geographic DWithin queries.')
                # Spherical distance calculation parameter should be in meters.
                dist_param = dist.m
            else:
                dist_param = getattr(dist, Distance.unit_attname(self._unit_name))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = dist

        if SpatialBackend.postgis and self.geodetic and lookup_type != 'dwithin' and option == 'spheroid':
            # On PostGIS, by default `ST_distance_sphere` is used; but if the
            # accuracy of `ST_distance_spheroid` is needed than the spheroid
            # needs to be passed to the SQL stored procedure.
            return [gqn(self._spheroid), dist_param]
        else:
            return [dist_param]
Exemplo n.º 6
0
    def get_distance(self, dist_val, lookup_type):
        """
        Returns a distance number in units of the field.  For example, if 
        `D(km=1)` was passed in and the units of the field were in meters,
        then 1000 would be returned.
        """
        # Getting the distance parameter and any options.
        if len(dist_val) == 1: dist, option = dist_val[0], None
        else: dist, option = dist_val

        if isinstance(dist, Distance):
            if self.geodetic:
                # Won't allow Distance objects w/DWithin lookups on PostGIS.
                if SpatialBackend.postgis and lookup_type == 'dwithin':
                    raise TypeError(
                        'Only numeric values of degree units are allowed on geographic DWithin queries.'
                    )
                # Spherical distance calculation parameter should be in meters.
                dist_param = dist.m
            else:
                dist_param = getattr(dist,
                                     Distance.unit_attname(self._unit_name))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = dist

        if SpatialBackend.postgis and self.geodetic and lookup_type != 'dwithin' and option == 'spheroid':
            # On PostGIS, by default `ST_distance_sphere` is used; but if the
            # accuracy of `ST_distance_spheroid` is needed than the spheroid
            # needs to be passed to the SQL stored procedure.
            return [gqn(self._spheroid), dist_param]
        else:
            return [dist_param]
Exemplo n.º 7
0
 def get_distance(self, f, value, lookup_type):
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError(
                 'Only numeric values of degree units are allowed on '
                 'geodetic distance queries.'
             )
         dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
Exemplo n.º 8
0
 def distance_att(self, connection):
     dist_att = None
     if self.geo_field.geodetic(connection):
         if connection.features.supports_distance_geodetic:
             dist_att = 'm'
     else:
         units = self.geo_field.units_name(connection)
         if units:
             dist_att = DistanceMeasure.unit_attname(units)
     return dist_att
Exemplo n.º 9
0
 def get_distance_att_for_field(self, field):
     dist_att = None
     if field.geodetic(self.connection):
         if self.connection.features.supports_distance_geodetic:
             dist_att = 'm'
     else:
         units = field.units_name(self.connection)
         if units:
             dist_att = DistanceMeasure.unit_attname(units)
     return dist_att
Exemplo n.º 10
0
 def distance_att(self, connection):
     dist_att = None
     if self.geo_field.geodetic(connection):
         if connection.features.supports_distance_geodetic:
             dist_att = 'm'
     else:
         units = self.geo_field.units_name(connection)
         if units:
             dist_att = DistanceMeasure.unit_attname(units)
     return dist_att
Exemplo n.º 11
0
 def get_distance_att_for_field(self, field):
     dist_att = None
     if field.geodetic(self.connection):
         if self.connection.features.supports_distance_geodetic:
             dist_att = 'm'
     else:
         units = field.units_name(self.connection)
         if units:
             dist_att = DistanceMeasure.unit_attname(units)
     return dist_att
Exemplo n.º 12
0
 def get_distance(self, f, value, lookup_type):
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError(
                 'Only numeric values of degree units are allowed on '
                 'geodetic distance queries.'
             )
         dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 13
0
 def get_distance(self, f, value, lookup_type):
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError('SAP HANA does not support distance queries on '
                              'geometry fields with a geodetic coordinate system. '
                              'Distance objects; use a numeric value of your '
                              'distance in degrees instead.')
         else:
             dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 14
0
 def convert_value(self, value, expression, connection, context):
     if value is None:
         return None
     geo_field = GeometryField(srid=self.srid)  # Fake field to get SRID info
     if geo_field.geodetic(connection):
         dist_att = 'm'
     else:
         units = geo_field.units_name(connection)
         if units:
             dist_att = DistanceMeasure.unit_attname(units)
         else:
             dist_att = None
     if dist_att:
         return DistanceMeasure(**{dist_att: value})
     return value
Exemplo n.º 15
0
 def convert_value(self, value, expression, connection, context):
     if value is None:
         return None
     geo_field = self.geo_field
     if geo_field.geodetic(connection):
         dist_att = 'm'
     else:
         units = geo_field.units_name(connection)
         if units:
             dist_att = DistanceMeasure.unit_attname(units)
         else:
             dist_att = None
     if dist_att:
         return DistanceMeasure(**{dist_att: value})
     return value
Exemplo n.º 16
0
 def get_distance(self, f, value, lookup_type):
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError('SAP HANA does not support distance queries on '
                              'geometry fields with a geodetic coordinate system. '
                              'Distance objects; use a numeric value of your '
                              'distance in degrees instead.')
         else:
             dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
    def get_distance(self, f, dist_val, lookup_type, handle_spheroid=True):
        """
        Retrieve the distance parameters for the given geometry field,
        distance lookup value, and the distance lookup type.

        This is the most complex implementation of the spatial backends due to
        what is supported on geodetic geometry columns vs. what's available on
        projected geometry columns.  In addition, it has to take into account
        the geography column type.
        """
        # Getting the distance parameter
        value = dist_val[0]

        # Shorthand boolean flags.
        geodetic = f.geodetic(self.connection)
        geography = f.geography

        if isinstance(value, Distance):
            if geography:
                dist_param = value.m
            elif geodetic:
                if lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are '
                                     'allowed on geographic DWithin queries.')
                dist_param = value.m
            else:
                dist_param = getattr(
                    value,
                    Distance.unit_attname(f.units_name(self.connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = value

        params = [dist_param]
        # handle_spheroid *might* be dropped in Django 2.0 as PostGISDistanceOperator
        # also handles it (#25524).
        if handle_spheroid and len(dist_val) > 1:
            option = dist_val[1]
            if (not geography and geodetic and lookup_type != 'dwithin'
                    and option == 'spheroid'):
                # using distance_spheroid requires the spheroid of the field as
                # a parameter.
                params.insert(0, f._spheroid)
        return params
Exemplo n.º 18
0
    def get_distance(self, f, dist_val, lookup_type):
        """
        Retrieve the distance parameters for the given geometry field,
        distance lookup value, and the distance lookup type.

        This is the most complex implementation of the spatial backends due to
        what is supported on geodetic geometry columns vs. what's available on
        projected geometry columns.  In addition, it has to take into account
        the newly introduced geography column type introudced in PostGIS 1.5.
        """
        # Getting the distance parameter and any options.
        if len(dist_val) == 1:
            value, option = dist_val[0], None
        else:
            value, option = dist_val

        # Shorthand boolean flags.
        geodetic = f.geodetic(self.connection)
        geography = f.geography and self.geography

        if isinstance(value, Distance):
            if geography:
                dist_param = value.m
            elif geodetic:
                if lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are '
                                     'allowed on geographic DWithin queries.')
                dist_param = value.m
            else:
                dist_param = getattr(
                    value,
                    Distance.unit_attname(f.units_name(self.connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = value

        if (not geography and geodetic and lookup_type != 'dwithin'
                and option == 'spheroid'):
            # using distance_spheroid requires the spheroid of the field as
            # a parameter.
            return [f._spheroid, dist_param]
        else:
            return [dist_param]
Exemplo n.º 19
0
    def get_distance(self, f, dist_val, lookup_type, handle_spheroid=True):
        """
        Retrieve the distance parameters for the given geometry field,
        distance lookup value, and the distance lookup type.

        This is the most complex implementation of the spatial backends due to
        what is supported on geodetic geometry columns vs. what's available on
        projected geometry columns.  In addition, it has to take into account
        the geography column type.
        """
        # Getting the distance parameter
        value = dist_val[0]

        # Shorthand boolean flags.
        geodetic = f.geodetic(self.connection)
        geography = f.geography

        if isinstance(value, Distance):
            if geography:
                dist_param = value.m
            elif geodetic:
                if lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are '
                                     'allowed on geographic DWithin queries.')
                dist_param = value.m
            else:
                dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = value

        params = [dist_param]
        # handle_spheroid *might* be dropped in Django 2.0 as PostGISDistanceOperator
        # also handles it (#25524).
        if handle_spheroid and len(dist_val) > 1:
            option = dist_val[1]
            if (not geography and geodetic and lookup_type != 'dwithin'
                    and option == 'spheroid'):
                # using distance_spheroid requires the spheroid of the field as
                # a parameter.
                params.insert(0, f._spheroid)
        return params
Exemplo n.º 20
0
    def get_distance(self, f, dist_val, lookup_type):
        """
        Retrieve the distance parameters for the given geometry field,
        distance lookup value, and the distance lookup type.

        This is the most complex implementation of the spatial backends due to
        what is supported on geodetic geometry columns vs. what's available on
        projected geometry columns.  In addition, it has to take into account
        the newly introduced geography column type introudced in PostGIS 1.5.
        """
        # Getting the distance parameter and any options.
        if len(dist_val) == 1:
            value, option = dist_val[0], None
        else:
            value, option = dist_val

        # Shorthand boolean flags.
        geodetic = f.geodetic(self.connection)
        geography = f.geography and self.geography

        if isinstance(value, Distance):
            if geography:
                dist_param = value.m
            elif geodetic:
                if lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are '
                                     'allowed on geographic DWithin queries.')
                dist_param = value.m
            else:
                dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = value

        if (not geography and geodetic and lookup_type != 'dwithin'
            and option == 'spheroid'):
            # using distance_spheroid requires the spheroid of the field as
            # a parameter.
            return [f._spheroid, dist_param]
        else:
            return [dist_param]
Exemplo n.º 21
0
 def get_distance(self, f, value, lookup_type):
     """
     Returns the distance parameters for the given geometry field,
     lookup value, and lookup type.  This is based on the Spatialite
     backend, since we don't currently support geography operations.
     """
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError('The SQL Server backend does not support '
                              'distance queries on geometry fields with '
                              'a geodetic coordinate system. Distance '
                              'objects; use a numeric value of your '
                              'distance in degrees instead.')
         else:
             dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 22
0
 def get_distance(self, f, value, lookup_type):
     """
     Return the distance parameters for the given geometry field,
     lookup value, and lookup type.
     """
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             if lookup_type == 'dwithin':
                 raise ValueError(
                     'Only numeric values of degree units are allowed on '
                     'geographic DWithin queries.'
                 )
             dist_param = value.m
         else:
             dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 23
0
 def get_distance(self, f, value, lookup_type):
     """
     Returns the distance parameters for the given geometry field,
     lookup value, and lookup type.  SpatiaLite only supports regular
     cartesian-based queries (no spheroid/sphere calculations for point
     geometries like PostGIS).
     """
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError('SpatiaLite does not support distance queries on '
                              'geometry fields with a geodetic coordinate system. '
                              'Distance objects; use a numeric value of your '
                              'distance in degrees instead.')
         else:
             dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 24
0
 def get_distance(self, f, value, lookup_type, **kwargs):
     """
     Return the distance parameters for the given geometry field,
     lookup value, and lookup type.
     """
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             if lookup_type == 'dwithin':
                 raise ValueError(
                     'Only numeric values of degree units are allowed on '
                     'geographic DWithin queries.'
                 )
             dist_param = value.m
         else:
             dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 25
0
 def get_distance(self, f, value, lookup_type):
     """
     Returns the distance parameters for the given geometry field,
     lookup value, and lookup type.  SpatiaLite only supports regular
     cartesian-based queries (no spheroid/sphere calculations for point
     geometries like PostGIS).
     """
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError('SpatiaLite does not support distance queries on '
                              'geometry fields with a geodetic coordinate system. '
                              'Distance objects; use a numeric value of your '
                              'distance in degrees instead.')
         else:
             dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 26
0
    def get_distance(self, f, value, lookup_type):
        """
        (A concoction of the SpatiaLite and PostGIS adapter code.)

        Assuming ST_Distance will return the distance in meters.
        """
        if not value:
            return []

        value = value[0]
        geodetic = f.geodetic(self.connection)

        if isinstance(value, Distance):
            if geodetic:
                dist_param = value.m
            else:
                dist_param = getattr(
                    value,
                    Distance.unit_attname(f.units_name(self.connection)))
        else:
            dist_param = value
        return [dist_param]
Exemplo n.º 27
0
 def get_distance(self, f, value, lookup_type):
     """
     Returns the distance parameters for the given geometry field,
     lookup value, and lookup type.  This is based on the Spatialite
     backend, since we don't currently support geography operations.
     """
     if not value:
         return []
     value = value[0]
     if isinstance(value, Distance):
         if f.geodetic(self.connection):
             raise ValueError('The SQL Server backend does not support '
                              'distance queries on geometry fields with '
                              'a geodetic coordinate system. Distance '
                              'objects; use a numeric value of your '
                              'distance in degrees instead.')
         else:
             dist_param = getattr(
                 value,
                 Distance.unit_attname(f.units_name(self.connection)))
     else:
         dist_param = value
     return [dist_param]
Exemplo n.º 28
0
    def get_distance(self, value, lookup_type, connection):
        """
        Returns a distance number in units of the field.  For example, if
        `D(km=1)` was passed in and the units of the field were in meters,
        then 1000 would be returned.
        """
        return connection.ops.get_distance(self, value, lookup_type)

        if isinstance(dist, Distance):
            if self.geodetic(connection):
                # Won't allow Distance objects w/DWithin lookups on PostGIS.
                if connection.ops.postgis and lookup_type == 'dwithin':
                    raise ValueError(
                        'Only numeric values of degree units are allowed on geographic DWithin queries.'
                    )

                # Spherical distance calculation parameter should be in meters.
                dist_param = dist.m
            else:
                dist_param = getattr(
                    dist, Distance.unit_attname(self.units_name(connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = dist

        if connection.ops.oracle and lookup_type == 'dwithin':
            dist_param = 'distance=%s' % dist_param

        if connection.ops.postgis and self.geodetic(
                connection
        ) and lookup_type != 'dwithin' and option == 'spheroid':
            # On PostGIS, by default `ST_distance_sphere` is used; but if the
            # accuracy of `ST_distance_spheroid` is needed than the spheroid
            # needs to be passed to the SQL stored procedure.
            return [self._spheroid, dist_param]
        else:
            return [dist_param]
Exemplo n.º 29
0
    def get_distance(self, f, value, lookup_type):
        """
        Returns the distance parameters given the value and the lookup type.
        On Oracle, geometry columns with a geodetic coordinate system behave
        implicitly like a geography column, and thus meters will be used as
        the distance parameter on them.
        """
        if not value:
            return []
        value = value[0]
        if isinstance(value, Distance):
            if f.geodetic(self.connection):
                dist_param = value.m
            else:
                dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
        else:
            dist_param = value

        # dwithin lookups on oracle require a special string parameter
        # that starts with "distance=".
        if lookup_type == 'dwithin':
            dist_param = 'distance=%s' % dist_param

        return [dist_param]
Exemplo n.º 30
0
import re
Exemplo n.º 31
0
from decimal import Decimal
Exemplo n.º 32
0
    def _distance_attribute(self, func, geom=None, tolerance=0.05, spheroid=False, **kwargs):
        """
        DRY routine for GeoQuerySet distance attribute routines.
        """
        # Setting up the distance procedure arguments.
        procedure_args, geo_field = self._spatial_setup(func, field_name=kwargs.get('field_name'))

        # If geodetic defaulting distance attribute to meters (Oracle and
        # PostGIS spherical distances return meters).  Otherwise, use the
        # units of the geometry field.
        connection = connections[self.db]
        geodetic = geo_field.geodetic(connection)
        geography = geo_field.geography

        if geodetic:
            dist_att = 'm'
        else:
            dist_att = Distance.unit_attname(geo_field.units_name(connection))

        # Shortcut booleans for what distance function we're using and
        # whether the geometry field is 3D.
        distance = func == 'distance'
        length = func == 'length'
        perimeter = func == 'perimeter'
        if not (distance or length or perimeter):
            raise ValueError('Unknown distance function: %s' % func)
        geom_3d = geo_field.dim == 3

        # The field's get_db_prep_lookup() is used to get any
        # extra distance parameters.  Here we set up the
        # parameters that will be passed in to field's function.
        lookup_params = [geom or 'POINT (0 0)', 0]

        # Getting the spatial backend operations.
        backend = connection.ops

        # If the spheroid calculation is desired, either by the `spheroid`
        # keyword or when calculating the length of geodetic field, make
        # sure the 'spheroid' distance setting string is passed in so we
        # get the correct spatial stored procedure.
        if spheroid or (backend.postgis and geodetic and
                        (not geography) and length):
            lookup_params.append('spheroid')
        lookup_params = geo_field.get_prep_value(lookup_params)
        params = geo_field.get_db_prep_lookup('distance_lte', lookup_params, connection=connection)

        # The `geom_args` flag is set to true if a geometry parameter was
        # passed in.
        geom_args = bool(geom)

        if backend.oracle:
            if distance:
                procedure_fmt = '%(geo_col)s,%(geom)s,%(tolerance)s'
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s,%(tolerance)s'
            procedure_args['tolerance'] = tolerance
        else:
            # Getting whether this field is in units of degrees since the field may have
            # been transformed via the `transform` GeoQuerySet method.
            srid = self.query.get_context('transformed_srid')
            if srid:
                u, unit_name, s = get_srid_info(srid, connection)
                geodetic = unit_name.lower() in geo_field.geodetic_units

            if geodetic and not connection.features.supports_distance_geodetic:
                raise ValueError(
                    'This database does not support linear distance '
                    'calculations on geodetic coordinate systems.'
                )

            if distance:
                if srid:
                    # Setting the `geom_args` flag to false because we want to handle
                    # transformation SQL here, rather than the way done by default
                    # (which will transform to the original SRID of the field rather
                    #  than to what was transformed to).
                    geom_args = False
                    procedure_fmt = '%s(%%(geo_col)s, %s)' % (backend.transform, srid)
                    if geom.srid is None or geom.srid == srid:
                        # If the geom parameter srid is None, it is assumed the coordinates
                        # are in the transformed units.  A placeholder is used for the
                        # geometry parameter.  `GeomFromText` constructor is also needed
                        # to wrap geom placeholder for SpatiaLite.
                        if backend.spatialite:
                            procedure_fmt += ', %s(%%%%s, %s)' % (backend.from_text, srid)
                        else:
                            procedure_fmt += ', %%s'
                    else:
                        # We need to transform the geom to the srid specified in `transform()`,
                        # so wrapping the geometry placeholder in transformation SQL.
                        # SpatiaLite also needs geometry placeholder wrapped in `GeomFromText`
                        # constructor.
                        if backend.spatialite:
                            procedure_fmt += (', %s(%s(%%%%s, %s), %s)' % (
                                backend.transform, backend.from_text,
                                geom.srid, srid))
                        else:
                            procedure_fmt += ', %s(%%%%s, %s)' % (backend.transform, srid)
                else:
                    # `transform()` was not used on this GeoQuerySet.
                    procedure_fmt = '%(geo_col)s,%(geom)s'

                if not geography and geodetic:
                    # Spherical distance calculation is needed (because the geographic
                    # field is geodetic). However, the PostGIS ST_distance_sphere/spheroid()
                    # procedures may only do queries from point columns to point geometries
                    # some error checking is required.
                    if not backend.geography:
                        if not isinstance(geo_field, PointField):
                            raise ValueError('Spherical distance calculation only supported on PointFields.')
                        if not str(Geometry(six.memoryview(params[0].ewkb)).geom_type) == 'Point':
                            raise ValueError(
                                'Spherical distance calculation only supported with '
                                'Point Geometry parameters'
                            )
                    # The `function` procedure argument needs to be set differently for
                    # geodetic distance calculations.
                    if spheroid:
                        # Call to distance_spheroid() requires spheroid param as well.
                        procedure_fmt += ",'%(spheroid)s'"
                        procedure_args.update({'function': backend.distance_spheroid, 'spheroid': params[1]})
                    else:
                        procedure_args.update({'function': backend.distance_sphere})
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s'
                if not geography and geodetic and length:
                    # There's no `length_sphere`, and `length_spheroid` also
                    # works on 3D geometries.
                    procedure_fmt += ",'%(spheroid)s'"
                    procedure_args.update({'function': backend.length_spheroid, 'spheroid': params[1]})
                elif geom_3d and connection.features.supports_3d_functions:
                    # Use 3D variants of perimeter and length routines on supported backends.
                    if perimeter:
                        procedure_args.update({'function': backend.perimeter3d})
                    elif length:
                        procedure_args.update({'function': backend.length3d})

        # Setting up the settings for `_spatial_attribute`.
        s = {'select_field': DistanceField(dist_att),
             'setup': False,
             'geo_field': geo_field,
             'procedure_args': procedure_args,
             'procedure_fmt': procedure_fmt,
             }
        if geom_args:
            s['geom_args'] = ('geom',)
            s['procedure_args']['geom'] = geom
        elif geom:
            # The geometry is passed in as a parameter because we handled
            # transformation conditions in this routine.
            s['select_params'] = [backend.Adapter(geom)]
        return self._spatial_attribute(func, s, **kwargs)
Exemplo n.º 33
0
    def _distance_attribute(self, func, geom=None, tolerance=0.05, spheroid=False, **kwargs):
        """
        DRY routine for GeoQuerySet distance attribute routines.
        """
        # Setting up the distance procedure arguments.
        procedure_args, geo_field = self._spatial_setup(func, field_name=kwargs.get('field_name', None))

        # If geodetic defaulting distance attribute to meters (Oracle and
        # PostGIS spherical distances return meters).  Otherwise, use the
        # units of the geometry field.
        if geo_field.geodetic:
            dist_att = 'm'
        else:
            dist_att = Distance.unit_attname(geo_field._unit_name)

        # Shortcut booleans for what distance function we're using.
        distance = func == 'distance'
        length = func == 'length'
        perimeter = func == 'perimeter'
        if not (distance or length or perimeter):
            raise ValueError('Unknown distance function: %s' % func)

        # The field's get_db_prep_lookup() is used to get any
        # extra distance parameters.  Here we set up the
        # parameters that will be passed in to field's function.
        lookup_params = [geom or 'POINT (0 0)', 0]

        # If the spheroid calculation is desired, either by the `spheroid`
        # keyword or wehn calculating the length of geodetic field, make
        # sure the 'spheroid' distance setting string is passed in so we
        # get the correct spatial stored procedure.
        if spheroid or (SpatialBackend.postgis and geo_field.geodetic and length):
            lookup_params.append('spheroid')
        where, params = geo_field.get_db_prep_lookup('distance_lte', lookup_params)

        # The `geom_args` flag is set to true if a geometry parameter was
        # passed in.
        geom_args = bool(geom)

        if SpatialBackend.oracle:
            if distance:
                procedure_fmt = '%(geo_col)s,%(geom)s,%(tolerance)s'
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s,%(tolerance)s'
            procedure_args['tolerance'] = tolerance
        else:
            # Getting whether this field is in units of degrees since the field may have
            # been transformed via the `transform` GeoQuerySet method.
            if self.query.transformed_srid:
                u, unit_name, s = get_srid_info(self.query.transformed_srid)
                geodetic = unit_name in geo_field.geodetic_units
            else:
                geodetic = geo_field.geodetic

            if distance:
                if self.query.transformed_srid:
                    # Setting the `geom_args` flag to false because we want to handle
                    # transformation SQL here, rather than the way done by default
                    # (which will transform to the original SRID of the field rather
                    #  than to what was transformed to).
                    geom_args = False
                    procedure_fmt = '%s(%%(geo_col)s, %s)' % (SpatialBackend.transform, self.query.transformed_srid)
                    if geom.srid is None or geom.srid == self.query.transformed_srid:
                        # If the geom parameter srid is None, it is assumed the coordinates
                        # are in the transformed units.  A placeholder is used for the
                        # geometry parameter.
                        procedure_fmt += ', %%s'
                    else:
                        # We need to transform the geom to the srid specified in `transform()`,
                        # so wrapping the geometry placeholder in transformation SQL.
                        procedure_fmt += ', %s(%%%%s, %s)' % (SpatialBackend.transform, self.query.transformed_srid)
                else:
                    # `transform()` was not used on this GeoQuerySet.
                    procedure_fmt  = '%(geo_col)s,%(geom)s'

                if geodetic:
                    # Spherical distance calculation is needed (because the geographic
                    # field is geodetic). However, the PostGIS ST_distance_sphere/spheroid()
                    # procedures may only do queries from point columns to point geometries
                    # some error checking is required.
                    if not isinstance(geo_field, PointField):
                        raise TypeError('Spherical distance calculation only supported on PointFields.')
                    if not str(SpatialBackend.Geometry(buffer(params[0].wkb)).geom_type) == 'Point':
                        raise TypeError('Spherical distance calculation only supported with Point Geometry parameters')
                    # The `function` procedure argument needs to be set differently for
                    # geodetic distance calculations.
                    if spheroid:
                        # Call to distance_spheroid() requires spheroid param as well.
                        procedure_fmt += ',%(spheroid)s'
                        procedure_args.update({'function' : SpatialBackend.distance_spheroid, 'spheroid' : where[1]})
                    else:
                        procedure_args.update({'function' : SpatialBackend.distance_sphere})
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s'
                if geodetic and length:
                    # There's no `length_sphere`
                    procedure_fmt += ',%(spheroid)s'
                    procedure_args.update({'function' : SpatialBackend.length_spheroid, 'spheroid' : where[1]})

        # Setting up the settings for `_spatial_attribute`.
        s = {'select_field' : DistanceField(dist_att),
             'setup' : False,
             'geo_field' : geo_field,
             'procedure_args' : procedure_args,
             'procedure_fmt' : procedure_fmt,
             }
        if geom_args:
            s['geom_args'] = ('geom',)
            s['procedure_args']['geom'] = geom
        elif geom:
            # The geometry is passed in as a parameter because we handled
            # transformation conditions in this routine.
            s['select_params'] = [SpatialBackend.Adaptor(geom)]
        return self._spatial_attribute(func, s, **kwargs)
Exemplo n.º 34
0
    def _distance_attribute(self,
                            func,
                            geom=None,
                            tolerance=0.05,
                            spheroid=False,
                            **kwargs):
        """
        DRY routine for GeoQuerySet distance attribute routines.
        """
        # Setting up the distance procedure arguments.
        procedure_args, geo_field = self._spatial_setup(func,
                                                        field_name=kwargs.get(
                                                            'field_name',
                                                            None))

        # If geodetic defaulting distance attribute to meters (Oracle and
        # PostGIS spherical distances return meters).  Otherwise, use the
        # units of the geometry field.
        if geo_field.geodetic:
            dist_att = 'm'
        else:
            dist_att = Distance.unit_attname(geo_field._unit_name)

        # Shortcut booleans for what distance function we're using.
        distance = func == 'distance'
        length = func == 'length'
        perimeter = func == 'perimeter'
        if not (distance or length or perimeter):
            raise ValueError('Unknown distance function: %s' % func)

        # The field's get_db_prep_lookup() is used to get any
        # extra distance parameters.  Here we set up the
        # parameters that will be passed in to field's function.
        lookup_params = [geom or 'POINT (0 0)', 0]

        # If the spheroid calculation is desired, either by the `spheroid`
        # keyword or wehn calculating the length of geodetic field, make
        # sure the 'spheroid' distance setting string is passed in so we
        # get the correct spatial stored procedure.
        if spheroid or (SpatialBackend.postgis and geo_field.geodetic
                        and length):
            lookup_params.append('spheroid')
        where, params = geo_field.get_db_prep_lookup('distance_lte',
                                                     lookup_params)

        # The `geom_args` flag is set to true if a geometry parameter was
        # passed in.
        geom_args = bool(geom)

        if SpatialBackend.oracle:
            if distance:
                procedure_fmt = '%(geo_col)s,%(geom)s,%(tolerance)s'
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s,%(tolerance)s'
            procedure_args['tolerance'] = tolerance
        else:
            # Getting whether this field is in units of degrees since the field may have
            # been transformed via the `transform` GeoQuerySet method.
            if self.query.transformed_srid:
                u, unit_name, s = get_srid_info(self.query.transformed_srid)
                geodetic = unit_name in geo_field.geodetic_units
            else:
                geodetic = geo_field.geodetic

            if distance:
                if self.query.transformed_srid:
                    # Setting the `geom_args` flag to false because we want to handle
                    # transformation SQL here, rather than the way done by default
                    # (which will transform to the original SRID of the field rather
                    #  than to what was transformed to).
                    geom_args = False
                    procedure_fmt = '%s(%%(geo_col)s, %s)' % (
                        SpatialBackend.transform, self.query.transformed_srid)
                    if geom.srid is None or geom.srid == self.query.transformed_srid:
                        # If the geom parameter srid is None, it is assumed the coordinates
                        # are in the transformed units.  A placeholder is used for the
                        # geometry parameter.
                        procedure_fmt += ', %%s'
                    else:
                        # We need to transform the geom to the srid specified in `transform()`,
                        # so wrapping the geometry placeholder in transformation SQL.
                        procedure_fmt += ', %s(%%%%s, %s)' % (
                            SpatialBackend.transform,
                            self.query.transformed_srid)
                else:
                    # `transform()` was not used on this GeoQuerySet.
                    procedure_fmt = '%(geo_col)s,%(geom)s'

                if geodetic:
                    # Spherical distance calculation is needed (because the geographic
                    # field is geodetic). However, the PostGIS ST_distance_sphere/spheroid()
                    # procedures may only do queries from point columns to point geometries
                    # some error checking is required.
                    if not isinstance(geo_field, PointField):
                        raise TypeError(
                            'Spherical distance calculation only supported on PointFields.'
                        )
                    if not str(
                            SpatialBackend.Geometry(buffer(
                                params[0].wkb)).geom_type) == 'Point':
                        raise TypeError(
                            'Spherical distance calculation only supported with Point Geometry parameters'
                        )
                    # The `function` procedure argument needs to be set differently for
                    # geodetic distance calculations.
                    if spheroid:
                        # Call to distance_spheroid() requires spheroid param as well.
                        procedure_fmt += ',%(spheroid)s'
                        procedure_args.update({
                            'function': SpatialBackend.distance_spheroid,
                            'spheroid': where[1]
                        })
                    else:
                        procedure_args.update(
                            {'function': SpatialBackend.distance_sphere})
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s'
                if geodetic and length:
                    # There's no `length_sphere`
                    procedure_fmt += ',%(spheroid)s'
                    procedure_args.update({
                        'function': SpatialBackend.length_spheroid,
                        'spheroid': where[1]
                    })

        # Setting up the settings for `_spatial_attribute`.
        s = {
            'select_field': DistanceField(dist_att),
            'setup': False,
            'geo_field': geo_field,
            'procedure_args': procedure_args,
            'procedure_fmt': procedure_fmt,
        }
        if geom_args:
            s['geom_args'] = ('geom', )
            s['procedure_args']['geom'] = geom
        elif geom:
            # The geometry is passed in as a parameter because we handled
            # transformation conditions in this routine.
            s['select_params'] = [SpatialBackend.Adaptor(geom)]
        return self._spatial_attribute(func, s, **kwargs)
Exemplo n.º 35
0
"""
Exemplo n.º 36
0
import warnings
Exemplo n.º 37
0
"""
Exemplo n.º 38
0
        value = dist_val[0]

        # Shorthand boolean flags.
        geodetic = f.geodetic(self.connection)
        geography = f.geography

        if isinstance(value, Distance):
            if geography:
                dist_param = value.m
            elif geodetic:
                if lookup_type == 'dwithin':
                    raise ValueError('Only numeric values of degree units are '
                                     'allowed on geographic DWithin queries.')
                dist_param = value.m
            else:
                dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
        else:
            # Assuming the distance is in the units of the field.
            dist_param = value

<<<<<<< HEAD
        params = [dist_param]
        # handle_spheroid *might* be dropped in Django 2.0 as PostGISDistanceOperator
        # also handles it (#25524).
        if handle_spheroid and len(dist_val) > 1:
            option = dist_val[1]
            if not geography and geodetic and lookup_type != 'dwithin' and option == 'spheroid':
                # using distance_spheroid requires the spheroid of the field as
                # a parameter.
                params.insert(0, f._spheroid)
        return params