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
-~----------~----~----~----~------~----~------~--~---