Author: jbronn
Date: 2007-07-25 21:18:26 -0500 (Wed, 25 Jul 2007)
New Revision: 5762

Modified:
   django/branches/gis/django/contrib/gis/db/models/fields/__init__.py
   django/branches/gis/django/contrib/gis/db/models/postgis.py
   django/branches/gis/django/contrib/gis/db/models/proxy.py
Log:
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.


Modified: django/branches/gis/django/contrib/gis/db/models/fields/__init__.py
===================================================================
--- django/branches/gis/django/contrib/gis/db/models/fields/__init__.py 
2007-07-26 02:00:38 UTC (rev 5761)
+++ django/branches/gis/django/contrib/gis/db/models/fields/__init__.py 
2007-07-26 02:18:26 UTC (rev 5762)
@@ -5,10 +5,9 @@
 from django.contrib.gis.oldforms import WKTField
 from django.utils.functional import curry
 from django.contrib.gis.geos import GEOSGeometry, GEOSException
+from types import StringType
 
 #TODO: Flesh out widgets.
-#TODO: GEOS and GDAL/OGR operations through fields as proxy.
-#TODO: pythonic usage, like "for point in zip.polygon" and "if point in 
polygon".
 
 class GeometryField(Field):
     "The base GIS field -- maps to the OpenGIS Specification Geometry type."
@@ -114,16 +113,45 @@
         return "NoField"
                                                                 
     def get_db_prep_lookup(self, lookup_type, value):
-        """Returns field's value prepared for database lookup; the SRID of the 
geometry is
-        included by default in these queries."""
+        "Returns field's value prepared for database lookup, accepts WKT and 
GEOS Geometries for the value."
+        if not bool(value): return None
         if lookup_type in POSTGIS_TERMS:
-            return [value and ("SRID=%d;%s" % (self._srid, value)) or None]
-        raise TypeError("Field has invalid lookup: %s" % lookup_type)
+            if isinstance(value, GEOSGeometry):
+                # GEOSGeometry instance passed in.
+                if value.srid != self._srid:
+                    # Returning a dictionary instructs the parse_lookup() to 
add what's in the 'where' key
+                    #  to the where parameters, since we need to transform the 
geometry in the query.
+                    return {'where' : "Transform(%s,%s)",
+                            'params' : [value, self._srid]
+                            }
+                else:
+                    # Just return the GEOSGeometry, it has its own psycopg2 
adaptor.
+                    return [value]
+            elif isinstance(value, StringType):
+                # String instance passed in, assuming WKT.
+                # TODO: Any validation needed here to prevent SQL injection?
+                return ["SRID=%d;%s" % (self._srid, value)]
+            else:
+                raise TypeError("Invalid type (%s) used for field lookup 
value." % str(type(value)))
+        else:
+            raise TypeError("Field has invalid lookup: %s" % lookup_type)
 
     def get_db_prep_save(self, value):
-        "Making sure the SRID is included before saving."
-        return value and ("SRID=%d;%s" % (self._srid, value)) or None
+        "Prepares the value for saving in the database."
+        if not bool(value): return None
+        if isinstance(value, GEOSGeometry):
+            return value
+        else:
+            return ("SRID=%d;%s" % (self._srid, wkt))
 
+    def get_placeholder(self, value):
+        "Provides a proper substitution value for "
+        if isinstance(value, GEOSGeometry) and value.srid != self._srid:
+            # Adding Transform() to the SQL placeholder.
+            return 'Transform(%%s, %s)' % self._srid
+        else:
+            return '%s'
+
     def get_manipulator_field_objs(self):
         "Using the WKTField (defined above) to be our manipulator."
         return [WKTField]

Modified: django/branches/gis/django/contrib/gis/db/models/postgis.py
===================================================================
--- django/branches/gis/django/contrib/gis/db/models/postgis.py 2007-07-26 
02:00:38 UTC (rev 5761)
+++ django/branches/gis/django/contrib/gis/db/models/postgis.py 2007-07-26 
02:18:26 UTC (rev 5762)
@@ -1,7 +1,7 @@
 # This module is meant to re-define the helper routines used by the
 # django.db.models.query objects to be customized for PostGIS.
 from django.db import backend
-from django.db.models.query import LOOKUP_SEPARATOR, find_field, FieldFound, 
QUERY_TERMS, get_where_clause
+from django.db.models.query import LOOKUP_SEPARATOR, field_choices, 
find_field, FieldFound, QUERY_TERMS, get_where_clause
 from django.utils.datastructures import SortedDict
 
 # PostGIS-specific operators. The commented descriptions of these
@@ -84,6 +84,12 @@
 
     raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type)
 
+####    query.py overloaded functions    ####
+# parse_lookup() and lookup_inner() are modified from their 
django/db/models/query.py
+#  counterparts to support constructing SQL for geographic queries.
+#
+# Status: Synced with r5609.
+#
 def parse_lookup(kwarg_items, opts):
     # Helper function that handles converting API kwargs
     # (e.g. "name__exact": "tom") to SQL.
@@ -117,7 +123,6 @@
         # If there is only one part, or the last part is not a query
         # term, assume that the query is an __exact
         lookup_type = path.pop()
-
         if lookup_type == 'pk':
             lookup_type = 'exact'
             path.append(None)
@@ -133,6 +138,8 @@
             # all uses of None as a query value.
             if lookup_type != 'exact':
                 raise ValueError, "Cannot use None as a query value"
+        elif callable(value):
+            value = value()
 
         joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, 
opts.db_table, None)
         joins.update(joins2)
@@ -206,7 +213,6 @@
 
         # Does the name belong to a one-to-one, many-to-one, or regular field?
         field = find_field(name, current_opts.fields, False)
-
         if field:
             if field.rel: # One-to-One/Many-to-one field
                 new_table = current_table + '__' + name
@@ -225,7 +231,11 @@
     except FieldFound: # Match found, loop has been shortcut.
         pass
     else: # No match found.
-        raise TypeError, "Cannot resolve keyword '%s' into field" % name
+        choices = field_choices(current_opts.many_to_many, False) + \
+            field_choices(current_opts.get_all_related_many_to_many_objects(), 
True) + \
+            field_choices(current_opts.get_all_related_objects(), True) + \
+            field_choices(current_opts.fields, False)
+        raise TypeError, "Cannot resolve keyword '%s' into field. Choices are: 
%s" % (name, ", ".join(choices))
 
     # Check whether an intermediate join is required between current_table
     # and new_table.
@@ -298,9 +308,20 @@
         # If the field is a geometry field, then the WHERE clause will need to 
be obtained
         # with the get_geo_where_clause()
         if hasattr(field, '_geom'):
-            where.append(get_geo_where_clause(lookup_type, current_table + 
'.', column, value))
+            # Getting the geographic where clause.
+            gwc = get_geo_where_clause(lookup_type, current_table + '.', 
column, value)
+
+            # Getting the geographic parameters from the field.
+            geo_params = field.get_db_prep_lookup(lookup_type, value)
+     
+            # If a dictionary was passed back from the field modify the where 
clause.
+            if isinstance(geo_params, dict):
+                gwc = gwc % geo_params['where']
+                geo_params = geo_params['params']
+            where.append(gwc)
+            params.extend(geo_params)
         else:
             where.append(get_where_clause(lookup_type, current_table + '.', 
column, value))
-        params.extend(field.get_db_prep_lookup(lookup_type, value))
+            params.extend(field.get_db_prep_lookup(lookup_type, value))
 
     return joins, where, params

Modified: django/branches/gis/django/contrib/gis/db/models/proxy.py
===================================================================
--- django/branches/gis/django/contrib/gis/db/models/proxy.py   2007-07-26 
02:00:38 UTC (rev 5761)
+++ django/branches/gis/django/contrib/gis/db/models/proxy.py   2007-07-26 
02:18:26 UTC (rev 5762)
@@ -24,7 +24,7 @@
     def __set__(self, obj, value): 
         if isinstance(value, GEOSGeometry): 
             if value and ((value.srid is None) and (self._field._srid is not 
None)): 
-                value.set_srid(self._field._srid) 
+                value.srid = self._field._srid
      
         obj.__dict__[self._field.attname] = value 
         return value 


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to