PageRenderTime 10ms CodeModel.GetById 1ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/gis/db/models/sql/query.py

https://code.google.com/p/mango-py/
Python | 119 lines | 75 code | 11 blank | 33 comment | 12 complexity | 62ed891af61c0877616ee118411f3598 MD5 | raw file
  1from django.db import connections
  2from django.db.models.query import sql
  3
  4from django.contrib.gis.db.models.fields import GeometryField
  5from django.contrib.gis.db.models.sql import aggregates as gis_aggregates
  6from django.contrib.gis.db.models.sql.conversion import AreaField, DistanceField, GeomField
  7from django.contrib.gis.db.models.sql.where import GeoWhereNode
  8from django.contrib.gis.geometry.backend import Geometry
  9from django.contrib.gis.measure import Area, Distance
 10
 11
 12ALL_TERMS = dict([(x, None) for x in (
 13            'bbcontains', 'bboverlaps', 'contained', 'contains',
 14            'contains_properly', 'coveredby', 'covers', 'crosses', 'disjoint',
 15            'distance_gt', 'distance_gte', 'distance_lt', 'distance_lte',
 16            'dwithin', 'equals', 'exact',
 17            'intersects', 'overlaps', 'relate', 'same_as', 'touches', 'within',
 18            'left', 'right', 'overlaps_left', 'overlaps_right',
 19            'overlaps_above', 'overlaps_below',
 20            'strictly_above', 'strictly_below'
 21            )])
 22ALL_TERMS.update(sql.constants.QUERY_TERMS)
 23
 24class GeoQuery(sql.Query):
 25    """
 26    A single spatial SQL query.
 27    """
 28    # Overridding the valid query terms.
 29    query_terms = ALL_TERMS
 30    aggregates_module = gis_aggregates
 31
 32    compiler = 'GeoSQLCompiler'
 33
 34    #### Methods overridden from the base Query class ####
 35    def __init__(self, model, where=GeoWhereNode):
 36        super(GeoQuery, self).__init__(model, where)
 37        # The following attributes are customized for the GeoQuerySet.
 38        # The GeoWhereNode and SpatialBackend classes contain backend-specific
 39        # routines and functions.
 40        self.custom_select = {}
 41        self.transformed_srid = None
 42        self.extra_select_fields = {}
 43
 44    def clone(self, *args, **kwargs):
 45        obj = super(GeoQuery, self).clone(*args, **kwargs)
 46        # Customized selection dictionary and transformed srid flag have
 47        # to also be added to obj.
 48        obj.custom_select = self.custom_select.copy()
 49        obj.transformed_srid = self.transformed_srid
 50        obj.extra_select_fields = self.extra_select_fields.copy()
 51        return obj
 52
 53    def convert_values(self, value, field, connection):
 54        """
 55        Using the same routines that Oracle does we can convert our
 56        extra selection objects into Geometry and Distance objects.
 57        TODO: Make converted objects 'lazy' for less overhead.
 58        """
 59        if connection.ops.oracle:
 60            # Running through Oracle's first.
 61            value = super(GeoQuery, self).convert_values(value, field or GeomField(), connection)
 62
 63        if value is None:
 64            # Output from spatial function is NULL (e.g., called
 65            # function on a geometry field with NULL value).
 66            pass
 67        elif isinstance(field, DistanceField):
 68            # Using the field's distance attribute, can instantiate
 69            # `Distance` with the right context.
 70            value = Distance(**{field.distance_att : value})
 71        elif isinstance(field, AreaField):
 72            value = Area(**{field.area_att : value})
 73        elif isinstance(field, (GeomField, GeometryField)) and value:
 74            value = Geometry(value)
 75        return value
 76
 77    def get_aggregation(self, using):
 78        # Remove any aggregates marked for reduction from the subquery
 79        # and move them to the outer AggregateQuery.
 80        connection = connections[using]
 81        for alias, aggregate in self.aggregate_select.items():
 82            if isinstance(aggregate, gis_aggregates.GeoAggregate):
 83                if not getattr(aggregate, 'is_extent', False) or connection.ops.oracle:
 84                    self.extra_select_fields[alias] = GeomField()
 85        return super(GeoQuery, self).get_aggregation(using)
 86
 87    def resolve_aggregate(self, value, aggregate, connection):
 88        """
 89        Overridden from GeoQuery's normalize to handle the conversion of
 90        GeoAggregate objects.
 91        """
 92        if isinstance(aggregate, self.aggregates_module.GeoAggregate):
 93            if aggregate.is_extent:
 94                if aggregate.is_extent == '3D':
 95                    return connection.ops.convert_extent3d(value)
 96                else:
 97                    return connection.ops.convert_extent(value)
 98            else:
 99                return connection.ops.convert_geom(value, aggregate.source)
100        else:
101            return super(GeoQuery, self).resolve_aggregate(value, aggregate, connection)
102
103    # Private API utilities, subject to change.
104    def _geo_field(self, field_name=None):
105        """
106        Returns the first Geometry field encountered; or specified via the
107        `field_name` keyword.  The `field_name` may be a string specifying
108        the geometry field on this GeoQuery's model, or a lookup string
109        to a geometry field via a ForeignKey relation.
110        """
111        if field_name is None:
112            # Incrementing until the first geographic field is found.
113            for fld in self.model._meta.fields:
114                if isinstance(fld, GeometryField): return fld
115            return False
116        else:
117            # Otherwise, check by the given field name -- which may be
118            # a lookup to a _related_ geographic field.
119            return GeoWhereNode._check_geo_field(self.model._meta, field_name)