PageRenderTime 41ms CodeModel.GetById 30ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://code.google.com/p/mango-py/
Python | 89 lines | 65 code | 7 blank | 17 comment | 9 complexity | 1aa4846fe64700a94cca0806b49d0948 MD5 | raw file
 1from django.db.models.fields import Field, FieldDoesNotExist
 2from django.db.models.sql.constants import LOOKUP_SEP
 3from django.db.models.sql.expressions import SQLEvaluator
 4from django.db.models.sql.where import Constraint, WhereNode
 5from django.contrib.gis.db.models.fields import GeometryField
 6
 7class GeoConstraint(Constraint):
 8    """
 9    This subclass overrides `process` to better handle geographic SQL
10    construction.
11    """
12    def __init__(self, init_constraint):
13        self.alias = init_constraint.alias
14        self.col = init_constraint.col
15        self.field = init_constraint.field
16
17    def process(self, lookup_type, value, connection):
18        if isinstance(value, SQLEvaluator):
19            # Make sure the F Expression destination field exists, and
20            # set an `srid` attribute with the same as that of the
21            # destination.
22            geo_fld = GeoWhereNode._check_geo_field(value.opts, value.expression.name)
23            if not geo_fld:
24                raise ValueError('No geographic field found in expression.')
25            value.srid = geo_fld.srid
26        db_type = self.field.db_type(connection=connection)
27        params = self.field.get_db_prep_lookup(lookup_type, value, connection=connection)
28        return (self.alias, self.col, db_type), params
29
30class GeoWhereNode(WhereNode):
31    """
32    Used to represent the SQL where-clause for spatial databases --
33    these are tied to the GeoQuery class that created it.
34    """
35    def add(self, data, connector):
36        if isinstance(data, (list, tuple)):
37            obj, lookup_type, value = data
38            if ( isinstance(obj, Constraint) and
39                 isinstance(obj.field, GeometryField) ):
40                data = (GeoConstraint(obj), lookup_type, value)
41        super(GeoWhereNode, self).add(data, connector)
42
43    def make_atom(self, child, qn, connection):
44        lvalue, lookup_type, value_annot, params_or_value = child
45        if isinstance(lvalue, GeoConstraint):
46            data, params = lvalue.process(lookup_type, params_or_value, connection)
47            spatial_sql = connection.ops.spatial_lookup_sql(data, lookup_type, params_or_value, lvalue.field, qn)
48            return spatial_sql, params
49        else:
50            return super(GeoWhereNode, self).make_atom(child, qn, connection)
51
52    @classmethod
53    def _check_geo_field(cls, opts, lookup):
54        """
55        Utility for checking the given lookup with the given model options.
56        The lookup is a string either specifying the geographic field, e.g.
57        'point, 'the_geom', or a related lookup on a geographic field like
58        'address__point'.
59
60        If a GeometryField exists according to the given lookup on the model
61        options, it will be returned.  Otherwise returns None.
62        """
63        # This takes into account the situation where the lookup is a
64        # lookup to a related geographic field, e.g., 'address__point'.
65        field_list = lookup.split(LOOKUP_SEP)
66
67        # Reversing so list operates like a queue of related lookups,
68        # and popping the top lookup.
69        field_list.reverse()
70        fld_name = field_list.pop()
71
72        try:
73            geo_fld = opts.get_field(fld_name)
74            # If the field list is still around, then it means that the
75            # lookup was for a geometry field across a relationship --
76            # thus we keep on getting the related model options and the
77            # model field associated with the next field in the list
78            # until there's no more left.
79            while len(field_list):
80                opts = geo_fld.rel.to._meta
81                geo_fld = opts.get_field(field_list.pop())
82        except (FieldDoesNotExist, AttributeError):
83            return False
84
85        # Finally, make sure we got a Geographic field and return.
86        if isinstance(geo_fld, GeometryField):
87            return geo_fld
88        else:
89            return False