Django

Code

Changeset 5762

Show
Ignore:
Timestamp:
07/25/07 21:18:26 (1 year ago)
Author:
jbronn
Message:

gis: geographic queries may now take geos geometry objects as an argument and geometry objects with different srid's are automatically transformed to the srid of the field; synced up parse_lookup() and lookup_inner() to r5609; minor change in GeometryProxy?.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/gis/django/contrib/gis/db/models/fields/__init__.py

    r5657 r5762  
    66from django.utils.functional import curry 
    77from django.contrib.gis.geos import GEOSGeometry, GEOSException 
     8from types import StringType 
    89 
    910#TODO: Flesh out widgets. 
    10 #TODO: GEOS and GDAL/OGR operations through fields as proxy. 
    11 #TODO: pythonic usage, like "for point in zip.polygon" and "if point in polygon". 
    1211 
    1312class GeometryField(Field): 
     
    115114                                                                 
    116115    def get_db_prep_lookup(self, lookup_type, value): 
    117         """Returns field's value prepared for database lookup; the SRID of the geometry is 
    118         included by default in these queries.""" 
     116        "Returns field's value prepared for database lookup, accepts WKT and GEOS Geometries for the value." 
     117        if not bool(value): return None 
    119118        if lookup_type in POSTGIS_TERMS: 
    120             return [value and ("SRID=%d;%s" % (self._srid, value)) or None] 
    121         raise TypeError("Field has invalid lookup: %s" % lookup_type) 
     119            if isinstance(value, GEOSGeometry): 
     120                # GEOSGeometry instance passed in. 
     121                if value.srid != self._srid: 
     122                    # Returning a dictionary instructs the parse_lookup() to add what's in the 'where' key 
     123                    #  to the where parameters, since we need to transform the geometry in the query. 
     124                    return {'where' : "Transform(%s,%s)", 
     125                            'params' : [value, self._srid] 
     126                            } 
     127                else: 
     128                    # Just return the GEOSGeometry, it has its own psycopg2 adaptor. 
     129                    return [value] 
     130            elif isinstance(value, StringType): 
     131                # String instance passed in, assuming WKT. 
     132                # TODO: Any validation needed here to prevent SQL injection? 
     133                return ["SRID=%d;%s" % (self._srid, value)] 
     134            else: 
     135                raise TypeError("Invalid type (%s) used for field lookup value." % str(type(value))) 
     136        else: 
     137            raise TypeError("Field has invalid lookup: %s" % lookup_type) 
    122138 
    123139    def get_db_prep_save(self, value): 
    124         "Making sure the SRID is included before saving." 
    125         return value and ("SRID=%d;%s" % (self._srid, value)) or None 
     140        "Prepares the value for saving in the database." 
     141        if not bool(value): return None 
     142        if isinstance(value, GEOSGeometry): 
     143            return value 
     144        else: 
     145            return ("SRID=%d;%s" % (self._srid, wkt)) 
     146 
     147    def get_placeholder(self, value): 
     148        "Provides a proper substitution value for " 
     149        if isinstance(value, GEOSGeometry) and value.srid != self._srid: 
     150            # Adding Transform() to the SQL placeholder. 
     151            return 'Transform(%%s, %s)' % self._srid 
     152        else: 
     153            return '%s' 
    126154 
    127155    def get_manipulator_field_objs(self): 
  • django/branches/gis/django/contrib/gis/db/models/postgis.py

    r5657 r5762  
    22# django.db.models.query objects to be customized for PostGIS. 
    33from django.db import backend 
    4 from django.db.models.query import LOOKUP_SEPARATOR, find_field, FieldFound, QUERY_TERMS, get_where_clause 
     4from django.db.models.query import LOOKUP_SEPARATOR, field_choices, find_field, FieldFound, QUERY_TERMS, get_where_clause 
    55from django.utils.datastructures import SortedDict 
    66 
     
    8585    raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type) 
    8686 
     87####    query.py overloaded functions    #### 
     88# parse_lookup() and lookup_inner() are modified from their django/db/models/query.py 
     89#  counterparts to support constructing SQL for geographic queries. 
     90# 
     91# Status: Synced with r5609. 
     92# 
    8793def parse_lookup(kwarg_items, opts): 
    8894    # Helper function that handles converting API kwargs 
     
    118124        # term, assume that the query is an __exact 
    119125        lookup_type = path.pop() 
    120  
    121126        if lookup_type == 'pk': 
    122127            lookup_type = 'exact' 
     
    134139            if lookup_type != 'exact': 
    135140                raise ValueError, "Cannot use None as a query value" 
     141        elif callable(value): 
     142            value = value() 
    136143 
    137144        joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None) 
     
    207214        # Does the name belong to a one-to-one, many-to-one, or regular field? 
    208215        field = find_field(name, current_opts.fields, False) 
    209  
    210216        if field: 
    211217            if field.rel: # One-to-One/Many-to-one field 
     
    226232        pass 
    227233    else: # No match found. 
    228         raise TypeError, "Cannot resolve keyword '%s' into field" % name 
     234        choices = field_choices(current_opts.many_to_many, False) + \ 
     235            field_choices(current_opts.get_all_related_many_to_many_objects(), True) + \ 
     236            field_choices(current_opts.get_all_related_objects(), True) + \ 
     237            field_choices(current_opts.fields, False) 
     238        raise TypeError, "Cannot resolve keyword '%s' into field. Choices are: %s" % (name, ", ".join(choices)) 
    229239 
    230240    # Check whether an intermediate join is required between current_table 
     
    299309        # with the get_geo_where_clause() 
    300310        if hasattr(field, '_geom'): 
    301             where.append(get_geo_where_clause(lookup_type, current_table + '.', column, value)) 
     311            # Getting the geographic where clause. 
     312            gwc = get_geo_where_clause(lookup_type, current_table + '.', column, value) 
     313 
     314            # Getting the geographic parameters from the field. 
     315            geo_params = field.get_db_prep_lookup(lookup_type, value) 
     316      
     317            # If a dictionary was passed back from the field modify the where clause. 
     318            if isinstance(geo_params, dict): 
     319                gwc = gwc % geo_params['where'] 
     320                geo_params = geo_params['params'] 
     321            where.append(gwc) 
     322            params.extend(geo_params) 
    302323        else: 
    303324            where.append(get_where_clause(lookup_type, current_table + '.', column, value)) 
    304         params.extend(field.get_db_prep_lookup(lookup_type, value)) 
     325            params.extend(field.get_db_prep_lookup(lookup_type, value)) 
    305326 
    306327    return joins, where, params 
  • django/branches/gis/django/contrib/gis/db/models/proxy.py

    r5657 r5762  
    2525        if isinstance(value, GEOSGeometry):  
    2626            if value and ((value.srid is None) and (self._field._srid is not None)):  
    27                 value.set_srid(self._field._srid)  
     27                value.srid = self._field._srid 
    2828      
    2929        obj.__dict__[self._field.attname] = value