Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

gis: spatial-backend enhancements:

 (1) GEOS no longer has psycopg2-specific routines, functionality now part of PostGIS adaptor in the spatial backend.
 (2) ST_GeomFromWKB() now used to enhance performance.
 (3) Moved GeometryProxy back to its original location.
 (4) Should resolve #5498, but not yet confirmed.
 (5) Test-sql files are now backend-specific.


git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6508 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit c049672a74673293e98104c223f034d5f5e08133 1 parent b6c8bba
@jbronn jbronn authored
View
68 django/contrib/gis/db/backend/__init__.py
@@ -11,32 +11,41 @@
the backend.
(4) The `parse_lookup` function, used for spatial SQL construction by
the GeoQuerySet.
- (5) The `create_spatial_db`, `geo_quotename`, and `get_geo_where_clause`
- routines (needed by `parse_lookup`.
+ (5) The `create_spatial_db`, and `get_geo_where_clause`
+ routines (needed by `parse_lookup`).
Currently only PostGIS is supported, but someday backends will be added for
additional spatial databases (e.g., Oracle, DB2).
"""
+from types import StringType, UnicodeType
from django.conf import settings
from django.db import connection
from django.db.models.query import field_choices, find_field, get_where_clause, \
FieldFound, LOOKUP_SEPARATOR, QUERY_TERMS
from django.utils.datastructures import SortedDict
+from django.contrib.gis.geos import GEOSGeometry
-# These routines default to False
-ASGML, ASKML, UNION = (False, False, False)
+# These routines (needed by GeoManager), default to False.
+ASGML, ASKML, TRANSFORM, UNION= (False, False, False, False)
if settings.DATABASE_ENGINE == 'postgresql_psycopg2':
# PostGIS is the spatial database, getting the rquired modules,
# renaming as necessary.
from django.contrib.gis.db.backend.postgis import \
PostGISField as GeoBackendField, POSTGIS_TERMS as GIS_TERMS, \
- PostGISProxy as GeometryProxy, \
- create_spatial_db, geo_quotename, get_geo_where_clause, \
- ASGML, ASKML, UNION
+ create_spatial_db, get_geo_where_clause, gqn, \
+ ASGML, ASKML, GEOM_SELECT, TRANSFORM, UNION
else:
raise NotImplementedError('No Geographic Backend exists for %s' % settings.DATABASE_NAME)
+def geo_quotename(value):
+ """
+ Returns the quotation used on a given Geometry value using the geometry
+ quoting from the backend (the `gqn` function).
+ """
+ if isinstance(value, (StringType, UnicodeType)): return gqn(value)
+ else: return str(value)
+
#### 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.
@@ -263,38 +272,29 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
# 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'):
- # Do we have multiple arguments, e.g., ST_Relate, ST_DWithin lookup types
- # need more than argument.
+ # Do we have multiple arguments, e.g., `relate`, `dwithin` lookup types
+ # need more than argument.
multiple_args = isinstance(value, tuple)
- # Getting the geographic where clause.
- gwc = get_geo_where_clause(lookup_type, current_table + '.', column, value)
-
- # Getting the geographic parameters from the field.
+ # Getting the preparation SQL object from the field.
if multiple_args:
- geo_params = field.get_db_prep_lookup(lookup_type, value[0])
+ geo_prep = field.get_db_prep_lookup(lookup_type, value[0])
else:
- geo_params = field.get_db_prep_lookup(lookup_type, value)
-
- # If a dictionary was passed back from the field modify the where clause.
- param_dict = isinstance(geo_params, dict)
- if param_dict:
- subst_list = geo_params['where']
- if multiple_args: subst_list += map(geo_quotename, value[1:])
- geo_params = geo_params['params']
- gwc = gwc % tuple(subst_list)
- elif multiple_args:
- # Modify the where clause if we have multiple arguments -- the
- # first substitution will be for another placeholder (for the
- # geometry) since it is already apart of geo_params.
- subst_list = ['%s']
- subst_list += map(geo_quotename, value[1:])
- gwc = gwc % tuple(subst_list)
-
- # Finally, appending onto the WHERE clause, and extending with any
- # additional parameters.
+ geo_prep = field.get_db_prep_lookup(lookup_type, value)
+
+ # Getting the adapted geometry from the field.
+ gwc = get_geo_where_clause(lookup_type, current_table + '.', column, value)
+
+ # A GeoFieldSQL object is returned by `get_db_prep_lookup` --
+ # getting the substitution list and the geographic parameters.
+ subst_list = geo_prep.where
+ if multiple_args: subst_list += map(geo_quotename, value[1:])
+ gwc = gwc % tuple(subst_list)
+
+ # Finally, appending onto the WHERE clause, and extending with
+ # the additional parameters.
where.append(gwc)
- params.extend(geo_params)
+ params.extend(geo_prep.params)
else:
where.append(get_where_clause(lookup_type, current_table + '.', column, value, db_type))
params.extend(field.get_db_prep_lookup(lookup_type, value))
View
24 django/contrib/gis/db/backend/postgis/__init__.py
@@ -1,24 +1,10 @@
"""
The PostGIS spatial database backend module.
"""
-from django.contrib.gis.db.backend.postgis.query import \
- get_geo_where_clause, geo_quotename, \
- GEOM_FUNC_PREFIX, POSTGIS_TERMS, \
- MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2
from django.contrib.gis.db.backend.postgis.creation import create_spatial_db
-from django.contrib.gis.db.backend.postgis.field import PostGISField
+from django.contrib.gis.db.backend.postgis.field import PostGISField, gqn
from django.contrib.gis.db.backend.postgis.proxy import PostGISProxy
-
-# Functions used by GeoManager methods, and not via lookup types.
-if MAJOR_VERSION == 1:
- if MINOR_VERSION1 == 3:
- ASKML = 'ST_AsKML'
- ASGML = 'ST_AsGML'
- UNION = 'ST_Union'
- elif MINOR_VERSION1 == 2 and MINOR_VERSION2 >= 1:
- ASKML = 'AsKML'
- ASGML = 'AsGML'
- UNION = 'GeomUnion'
-
-
-
+from django.contrib.gis.db.backend.postgis.query import \
+ get_geo_where_clause, GEOM_FUNC_PREFIX, POSTGIS_TERMS, \
+ MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2, \
+ ASKML, ASGML, GEOM_FROM_TEXT, UNION, TRANSFORM, GEOM_SELECT
View
29 django/contrib/gis/db/backend/postgis/adaptor.py
@@ -0,0 +1,29 @@
+"""
+ This object provides quoting for GEOS geometries into PostgreSQL/PostGIS.
+"""
+
+from django.contrib.gis.db.backend.postgis.query import GEOM_FROM_WKB
+from psycopg2 import Binary
+from psycopg2.extensions import ISQLQuote
+
+class PostGISAdaptor(object):
+ def __init__(self, geom, srid):
+ "Initializes on the geometry and the SRID."
+ # Getting the WKB and the SRID
+ self.wkb = geom.wkb
+ self.srid = srid
+
+ def __conform__(self, proto):
+ # Does the given protocol conform to what Psycopg2 expects?
+ if proto == ISQLQuote:
+ return self
+ else:
+ raise Exception('Error implementing psycopg2 protocol. Is psycopg2 installed?')
+
+ def __str__(self):
+ return self.getquoted()
+
+ def getquoted(self):
+ "Returns a properly quoted string for use in PostgreSQL/PostGIS."
+ # Want to use WKB, so wrap with psycopg2 Binary() to quote properly.
+ return "%s(%s, %s)" % (GEOM_FROM_WKB, Binary(self.wkb), self.srid or -1)
View
94 django/contrib/gis/db/backend/postgis/field.py
@@ -1,7 +1,17 @@
+from types import StringType, UnicodeType
+from django.db import connection
from django.db.models.fields import Field # Django base Field class
from django.contrib.gis.geos import GEOSGeometry, GEOSException
-from django.contrib.gis.db.backend.postgis.query import POSTGIS_TERMS, geo_quotename as quotename
-from types import StringType
+from django.contrib.gis.db.backend.util import GeoFieldSQL
+from django.contrib.gis.db.backend.postgis.adaptor import PostGISAdaptor
+from django.contrib.gis.db.backend.postgis.query import POSTGIS_TERMS, TRANSFORM
+from psycopg2 import Binary
+
+# Quotename & geographic quotename, respectively
+qn = connection.ops.quote_name
+def gqn(value):
+ if isinstance(value, UnicodeType): value = value.encode('ascii')
+ return "'%s'" % value
class PostGISField(Field):
def _add_geom(self, style, db_table):
@@ -10,23 +20,23 @@ def _add_geom(self, style, db_table):
AddGeometryColumn(...) PostGIS (and OGC standard) stored procedure.
Takes the style object (provides syntax highlighting) and the
- database table as parameters.
+ database table as parameters.
"""
sql = style.SQL_KEYWORD('SELECT ') + \
style.SQL_TABLE('AddGeometryColumn') + '(' + \
- style.SQL_TABLE(quotename(db_table)) + ', ' + \
- style.SQL_FIELD(quotename(self.column)) + ', ' + \
+ style.SQL_TABLE(gqn(db_table)) + ', ' + \
+ style.SQL_FIELD(gqn(self.column)) + ', ' + \
style.SQL_FIELD(str(self._srid)) + ', ' + \
- style.SQL_COLTYPE(quotename(self._geom)) + ', ' + \
+ style.SQL_COLTYPE(gqn(self._geom)) + ', ' + \
style.SQL_KEYWORD(str(self._dim)) + ');'
if not self.null:
# Add a NOT NULL constraint to the field
sql += '\n' + \
style.SQL_KEYWORD('ALTER TABLE ') + \
- style.SQL_TABLE(quotename(db_table, dbl=True)) + \
+ style.SQL_TABLE(qn(db_table)) + \
style.SQL_KEYWORD(' ALTER ') + \
- style.SQL_FIELD(quotename(self.column, dbl=True)) + \
+ style.SQL_FIELD(qn(self.column)) + \
style.SQL_KEYWORD(' SET NOT NULL') + ';'
return sql
@@ -34,12 +44,12 @@ def _geom_index(self, style, db_table,
index_type='GIST', index_opts='GIST_GEOMETRY_OPS'):
"Creates a GiST index for this geometry field."
sql = style.SQL_KEYWORD('CREATE INDEX ') + \
- style.SQL_TABLE(quotename('%s_%s_id' % (db_table, self.column), dbl=True)) + \
+ style.SQL_TABLE(qn('%s_%s_id' % (db_table, self.column))) + \
style.SQL_KEYWORD(' ON ') + \
- style.SQL_TABLE(quotename(db_table, dbl=True)) + \
+ style.SQL_TABLE(qn(db_table)) + \
style.SQL_KEYWORD(' USING ') + \
style.SQL_COLTYPE(index_type) + ' ( ' + \
- style.SQL_FIELD(quotename(self.column, dbl=True)) + ' ' + \
+ style.SQL_FIELD(qn(self.column)) + ' ' + \
style.SQL_KEYWORD(index_opts) + ' );'
return sql
@@ -64,8 +74,8 @@ def _post_delete_sql(self, style, db_table):
"Drops the geometry column."
sql = style.SQL_KEYWORD('SELECT ') + \
style.SQL_KEYWORD('DropGeometryColumn') + '(' + \
- style.SQL_TABLE(quotename(db_table)) + ', ' + \
- style.SQL_FIELD(quotename(self.column)) + ');'
+ style.SQL_TABLE(gqn(db_table)) + ', ' + \
+ style.SQL_FIELD(gqn(self.column)) + ');'
return sql
def db_type(self):
@@ -81,26 +91,37 @@ def get_db_prep_lookup(self, lookup_type, value):
GEOS Geometries for the value.
"""
if lookup_type in POSTGIS_TERMS:
- if lookup_type == 'isnull': return [value] # special case for NULL geometries.
- if not bool(value): return [None] # If invalid value passed in.
+ # special case for isnull lookup
+ if lookup_type == 'isnull':
+ return GeoFieldSQL([], [value])
+
+ # When the input is not a GEOS geometry, attempt to construct one
+ # from the given string input.
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' : ["ST_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)]
+ pass
+ elif isinstance(value, (StringType, UnicodeType)):
+ try:
+ value = GEOSGeometry(value)
+ except GEOSException:
+ raise TypeError("Could not create geometry from lookup value: %s" % str(value))
+ else:
+ raise TypeError('Cannot use parameter of %s type as lookup parameter.' % type(value))
+
+ # Getting the SRID of the geometry, or defaulting to that of the field if
+ # it is None.
+ if value.srid is None: srid = self._srid
+ else: srid = value.srid
+
+ # The adaptor will be used by psycopg2 for quoting the WKB.
+ adapt = PostGISAdaptor(value, srid)
+
+ if srid != self._srid:
+ # Adding the necessary string substitutions and parameters
+ # to perform a geometry transformation.
+ return GeoFieldSQL(['%s(%%s,%%s)' % TRANSFORM],
+ [adapt, self._srid])
else:
- raise TypeError("Invalid type (%s) used for field lookup value." % str(type(value)))
+ return GeoFieldSQL(['%s'], [adapt])
else:
raise TypeError("Field has invalid lookup: %s" % lookup_type)
@@ -108,24 +129,25 @@ def get_db_prep_save(self, value):
"Prepares the value for saving in the database."
if not bool(value): return None
if isinstance(value, GEOSGeometry):
- return value
+ return PostGISAdaptor(value, value.srid)
else:
raise TypeError('Geometry Proxy should only return GEOSGeometry objects.')
def get_internal_type(self):
"""
- Returns NoField because a stored procedure is used by PostGIS to create the
+ Returns NoField because a stored procedure is used by PostGIS to create
+ the Geometry Fields.
"""
return 'NoField'
def get_placeholder(self, value):
"""
Provides a proper substitution value for Geometries that are not in the
- SRID of the field. Specifically, this routine will substitute in the
- ST_Transform() function call.
+ SRID of the field. Specifically, this routine will substitute in the
+ ST_Transform() function call.
"""
if isinstance(value, GEOSGeometry) and value.srid != self._srid:
# Adding Transform() to the SQL placeholder.
- return 'ST_Transform(%%s, %s)' % self._srid
+ return '%s(%%s, %s)' % (TRANSFORM, self._srid)
else:
return '%s'
View
62 django/contrib/gis/db/backend/postgis/query.py
@@ -1,11 +1,11 @@
"""
- This module contains the spatial lookup types, and the get_geo_where_clause()
- routine for PostGIS.
+ This module contains the spatial lookup types, and the get_geo_where_clause()
+ routine for PostGIS.
"""
from django.db import connection
from django.contrib.gis.db.backend.postgis.management import postgis_version_tuple
from types import StringType, UnicodeType
-quote_name = connection.ops.quote_name
+qn = connection.ops.quote_name
# Getting the PostGIS version information
POSTGIS_VERSION, MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2 = postgis_version_tuple()
@@ -121,21 +121,16 @@ def get_geom_func(lookup_type):
def get_geo_where_clause(lookup_type, table_prefix, field_name, value):
"Returns the SQL WHERE clause for use in PostGIS SQL construction."
if table_prefix.endswith('.'):
- table_prefix = quote_name(table_prefix[:-1])+'.'
- field_name = quote_name(field_name)
+ table_prefix = qn(table_prefix[:-1])+'.'
+ field_name = qn(field_name)
# See if a PostGIS operator matches the lookup type first
- try:
+ if lookup_type in POSTGIS_OPERATORS:
return '%s%s %s %%s' % (table_prefix, field_name, POSTGIS_OPERATORS[lookup_type])
- except KeyError:
- pass
# See if a PostGIS Geometry function matches the lookup type next
- try:
+ if lookup_type in POSTGIS_GEOMETRY_FUNCTIONS:
lookup_info = POSTGIS_GEOMETRY_FUNCTIONS[lookup_type]
- except KeyError:
- pass
- else:
# Lookup types that are tuples take tuple arguments, e.g., 'relate' and
# 'dwithin' lookup types.
if isinstance(lookup_info, tuple):
@@ -145,7 +140,7 @@ def get_geo_where_clause(lookup_type, table_prefix, field_name, value):
# Ensuring that a tuple _value_ was passed in from the user
if not isinstance(value, tuple) or len(value) != 2:
- raise TypeError('2-element tuple required for %s lookup type.' % lookup_type)
+ raise TypeError('2-element tuple required for `%s` lookup type.' % lookup_type)
# Ensuring the argument type matches what we expect.
if not isinstance(value[1], arg_type):
@@ -154,7 +149,7 @@ def get_geo_where_clause(lookup_type, table_prefix, field_name, value):
return "%s(%s%s, %%s, %%s)" % (func, table_prefix, field_name)
else:
# Returning the SQL necessary for the geometry function call. For example:
- # ST_Contains("geoapp_country"."poly", ST_GeomFromText(..))
+ # ST_Contains("geoapp_country"."poly", ST_GeomFromWKB(..))
return '%s(%s%s, %%s)' % (lookup_info, table_prefix, field_name)
# Handling 'isnull' lookup type
@@ -163,10 +158,35 @@ def get_geo_where_clause(lookup_type, table_prefix, field_name, value):
raise TypeError("Got invalid lookup_type: %s" % repr(lookup_type))
-def geo_quotename(value, dbl=False):
- "Returns the quotation used for PostGIS on a given value (uses single quotes by default)."
- if isinstance(value, (StringType, UnicodeType)):
- if dbl: return '"%s"' % value
- else: return "'%s'" % value
- else:
- return str(value)
+# Functions that we define manually.
+if MAJOR_VERSION == 1:
+ if MINOR_VERSION1 == 3:
+ # PostGIS versions 1.3.x
+ ASKML = 'ST_AsKML'
+ ASGML = 'ST_AsGML'
+ GEOM_FROM_TEXT = 'ST_GeomFromText'
+ GEOM_FROM_WKB = 'ST_GeomFromWKB'
+ UNION = 'ST_Union'
+ TRANSFORM = 'ST_Transform'
+ elif MINOR_VERSION1 == 2 and MINOR_VERSION2 >= 1:
+ # PostGIS versions 1.2.x
+ ASKML = 'AsKML'
+ ASGML = 'AsGML'
+ GEOM_FROM_TEXT = 'GeomFromText'
+ GEOM_FROM_WKB = 'GeomFromWKB'
+ UNION = 'GeomUnion'
+ TRANSFORM = 'Transform'
+ elif MINOR_VERSION1 == 1 and MINOR_VERSION2 >= 0:
+ # PostGIS versions 1.1.x
+ ASKML = False
+ ASGML = 'AsGML'
+ GEOM_FROM_TEXT = 'GeomFromText'
+ GEOM_FROM_WKB = 'GeomFromWKB'
+ TRANSFORM = 'Transform'
+ UNION = 'GeomUnion'
+
+# Custom selection not needed for PostGIS since GEOS geometries may be
+# instantiated directly from the HEXEWKB returned by default. If
+# WKT is needed for some reason in the future, this value may be changed,
+# 'AsText(%s)'
+GEOM_SELECT = None
View
8 django/contrib/gis/db/backend/util.py
@@ -0,0 +1,8 @@
+class GeoFieldSQL(object):
+ """
+ Container for passing values to `parse_lookup` from the various
+ backend geometry fields.
+ """
+ def __init__(self, where=[], params=[]):
+ self.where = where
+ self.params = params
View
2  django/contrib/gis/db/models/__init__.py
@@ -7,7 +7,7 @@
# The GeoQ object
from django.contrib.gis.db.models.query import GeoQ
-# The various PostGIS/OpenGIS enabled fields.
+# The geographic-enabled fields.
from django.contrib.gis.db.models.fields import \
GeometryField, PointField, LineStringField, PolygonField, \
MultiPointField, MultiLineStringField, MultiPolygonField, \
View
3  django/contrib/gis/db/models/fields/__init__.py
@@ -1,5 +1,6 @@
from django.conf import settings
-from django.contrib.gis.db.backend import GeoBackendField, GeometryProxy # these depend on the spatial database backend.
+from django.contrib.gis.db.backend import GeoBackendField # these depend on the spatial database backend.
+from django.contrib.gis.db.models.proxy import GeometryProxy
from django.contrib.gis.oldforms import WKTField
from django.contrib.gis.geos import GEOSGeometry
View
2  ...o/contrib/gis/db/backend/postgis/proxy.py → django/contrib/gis/db/models/proxy.py
@@ -8,7 +8,7 @@
from types import NoneType, StringType, UnicodeType
-class PostGISProxy(object):
+class GeometryProxy(object):
def __init__(self, klass, field):
"""
Proxy initializes on the given Geometry class (not an instance) and
View
33 django/contrib/gis/db/models/query.py
@@ -6,7 +6,7 @@
from django.utils.datastructures import SortedDict
from django.contrib.gis.db.models.fields import GeometryField
# parse_lookup depends on the spatial database backend.
-from django.contrib.gis.db.backend import parse_lookup, ASGML, ASKML, UNION
+from django.contrib.gis.db.backend import parse_lookup, ASGML, ASKML, GEOM_SELECT, TRANSFORM, UNION
from django.contrib.gis.geos import GEOSGeometry
class GeoQ(Q):
@@ -29,6 +29,11 @@ def __init__(self, model=None):
# For replacement fields in the SELECT.
self._custom_select = {}
+ # If GEOM_SELECT is defined in the backend, then it will be used
+ # for the selection format of the geometry column.
+ if GEOM_SELECT: self._geo_fmt = GEOM_SELECT
+ else: self._geo_fmt = '%s'
+
def _filter_or_exclude(self, mapper, *args, **kwargs):
# mapper is a callable used to transform Q objects,
# or None for identity transform
@@ -57,10 +62,21 @@ def _get_sql_clause(self):
# GeoQuerySet. Specifically, this allows operations to be done on fields
# in the SELECT, overriding their values -- this is different from using
# QuerySet.extra(select=foo) because extra() adds an an _additional_
- # field to be selected. Used in returning transformed geometries.
+ # field to be selected. Used in returning transformed geometries, and
+ # handling the selection of native database geometry formats.
for f in opts.fields:
- if f.column in self._custom_select: select.append(self._custom_select[f.column])
- else: select.append(self._field_column(f))
+ # Getting the selection format string.
+ if hasattr(f, '_geom'): sel_fmt = self._geo_fmt
+ else: sel_fmt = '%s'
+
+ # Getting the field selection substitution string
+ if f.column in self._custom_select:
+ fld_sel = self._custom_select[f.column]
+ else:
+ fld_sel = self._field_column(f)
+
+ # Appending the selection
+ select.append(sel_fmt % fld_sel)
tables = [quote_only_if_word(t) for t in self._tables]
joins = SortedDict()
@@ -204,13 +220,16 @@ def transform(self, field_name, srid=4326):
# Is the given field name a geographic field?
field = self.model._meta.get_field(field_name)
if not isinstance(field, GeometryField):
- raise TypeError('ST_Transform() only available for GeometryFields')
+ raise TypeError('%s() only available for GeometryFields' % TRANSFORM)
+
+ # If there's already custom select SQL.
+ col = self._custom_select.get(field.column, self._field_column(field))
# Setting the key for the field's column with the custom SELECT SQL to
# override the geometry column returned from the database.
self._custom_select[field.column] = \
- '(ST_Transform(%s, %s)) AS %s' % (self._field_column(field), srid,
- connection.ops.quote_name(field.column))
+ '(%s(%s, %s)) AS %s' % (TRANSFORM, col, srid,
+ connection.ops.quote_name(field.column))
return self._clone()
def union(self, field_name):
View
32 django/contrib/gis/geos/base.py
@@ -12,7 +12,7 @@
import re
from django.contrib.gis.geos.coordseq import GEOSCoordSeq, create_cs
from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError
-from django.contrib.gis.geos.libgeos import lgeos, HAS_NUMPY, ISQLQuote
+from django.contrib.gis.geos.libgeos import lgeos, HAS_NUMPY
from django.contrib.gis.geos.pointer import GEOSPointer, NULL_GEOM
# Trying to import GDAL libraries, if available. Have to place in
@@ -47,14 +47,15 @@ def __init__(self, geo_input, srid=None):
The `srid` keyword is used to specify the Source Reference Identifier
(SRID) number for this Geometry. If not set, the SRID will be None.
- """
-
+ """
+ from_hex = False
if isinstance(geo_input, UnicodeType):
# Encoding to ASCII, WKT or HEXEWKB doesn't need any more.
geo_input = geo_input.encode('ascii')
if isinstance(geo_input, StringType):
if hex_regex.match(geo_input):
# If the regex matches, the geometry is in HEX form.
+ from_hex = True
sz = c_size_t(len(geo_input))
buf = create_string_buffer(geo_input)
g = lgeos.GEOSGeomFromHEX_buf(buf, sz)
@@ -62,7 +63,7 @@ def __init__(self, geo_input, srid=None):
# Otherwise, the geometry is in WKT form.
g = lgeos.GEOSGeomFromWKT(c_char_p(geo_input))
else:
- raise GEOSException, 'given string input "%s" unrecognized as WKT or HEXEWKB.' % geo_input
+ raise GEOSException('String or unicode input unrecognized as WKT or HEXEWKB.')
elif isinstance(geo_input, (IntType, GEOSPointer)):
# When the input is either a memory address (an integer), or a
# GEOSPointer object.
@@ -85,6 +86,10 @@ def __init__(self, geo_input, srid=None):
# Setting the SRID, if given.
if srid and isinstance(srid, int): self.srid = srid
+ # Exported HEX from other GEOS geometries will have -1 SRID --
+ # set here to 0, when the SRID is not explicitly given.
+ if not srid and from_hex: self.srid = 0
+
# Setting the class type (e.g., 'Point', 'Polygon', etc.)
self.__class__ = GEOS_CLASSES[self.geom_type]
@@ -207,19 +212,6 @@ def _reassign(self, new_geom):
self.__class__ = GEOS_CLASSES[gtype]
if isinstance(self, (Polygon, GeometryCollection)): self._populate()
- #### Psycopg2 database adaptor routines ####
- def __conform__(self, proto):
- # Does the given protocol conform to what Psycopg2 expects?
- if proto == ISQLQuote:
- return self
- else:
- raise GEOSException, 'Error implementing psycopg2 protocol. Is psycopg2 installed?'
-
- def getquoted(self):
- "Returns a properly quoted string for use in PostgreSQL/PostGIS."
- # Using ST_GeomFromText(), corresponds to SQL/MM ISO standard.
- return "ST_GeomFromText('%s', %s)" % (self.wkt, self.srid or -1)
-
#### Coordinate Sequence Routines ####
@property
def has_cs(self):
@@ -425,7 +417,11 @@ def wkt(self):
@property
def hex(self):
- "Returns the HEXEWKB of the Geometry."
+ """
+ Returns the HEX of the Geometry -- please note that the SRID is not
+ included in this representation, because the GEOS C library uses
+ -1 by default, even if the SRID is set.
+ """
sz = c_size_t()
h = lgeos.GEOSGeomToHEX_buf(self._ptr(), byref(sz))
return string_at(h, sz.value)
View
6 django/contrib/gis/geos/libgeos.py
@@ -18,12 +18,6 @@
except ImportError:
HAS_NUMPY = False
-# Is psycopg2 available?
-try:
- from psycopg2.extensions import ISQLQuote
-except (ImportError, EnvironmentError):
- ISQLQuote = None
-
# Setting the appropriate name for the GEOS-C library, depending on which
# OS and POSIX platform we're running.
if os.name == 'nt':
View
0  django/contrib/gis/tests/geoapp/sql/city.sql → ...s/geoapp/sql/city.postgresql_psycopg2.sql
File renamed without changes
View
0  .../contrib/gis/tests/geoapp/sql/country.sql → ...eoapp/sql/country.postgresql_psycopg2.sql
File renamed without changes
View
0  ...go/contrib/gis/tests/geoapp/sql/state.sql → .../geoapp/sql/state.postgresql_psycopg2.sql
File renamed without changes

0 comments on commit c049672

Please sign in to comment.
Something went wrong with that request. Please try again.