summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/gis/db/backend/__init__.py (renamed from django/contrib/gis/db/models/postgis.py)109
-rw-r--r--django/contrib/gis/db/backend/postgis/__init__.py7
-rw-r--r--django/contrib/gis/db/backend/postgis/creation.py (renamed from django/contrib/gis/utils/spatial_db.py)0
-rw-r--r--django/contrib/gis/db/backend/postgis/field.py107
-rw-r--r--django/contrib/gis/db/backend/postgis/management.py36
-rw-r--r--django/contrib/gis/db/backend/postgis/query.py127
-rw-r--r--django/contrib/gis/db/models/fields/__init__.py111
-rw-r--r--django/contrib/gis/db/models/query.py2
-rw-r--r--django/contrib/gis/tests/__init__.py2
-rw-r--r--django/contrib/gis/tests/geoapp/tests.py2
10 files changed, 305 insertions, 198 deletions
diff --git a/django/contrib/gis/db/models/postgis.py b/django/contrib/gis/db/backend/__init__.py
index fe17b12499..afda586dea 100644
--- a/django/contrib/gis/db/models/postgis.py
+++ b/django/contrib/gis/db/backend/__init__.py
@@ -1,92 +1,29 @@
-# This module is meant to re-define the helper routines used by the
-# django.db.models.query objects to be customized for PostGIS.
+"""
+ This module provides the backend for spatial SQL construction with Django.
+
+ Specifically, this module will import the correct routines and modules
+ needed for GeoDjango
+
+ (1) GeoBackEndField, a base class needed for GeometryField.
+ (2) The parse_lookup() function, used for spatial SQL construction by
+ the GeoQuerySet.
+
+ Currently only PostGIS is supported, but someday backends will be aded for
+ additional spatial databases.
+"""
+from django.conf import settings
from django.db import backend
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
-# operators come from Section 6.2.2 of the official PostGIS documentation.
-POSTGIS_OPERATORS = {
- # The "&<" operator returns true if A's bounding box overlaps or is to the left of B's bounding box.
- 'overlaps_left' : '&< %s',
- # The "&>" operator returns true if A's bounding box overlaps or is to the right of B's bounding box.
- 'overlaps_right' : '&> %s',
- # The "<<" operator returns true if A's bounding box is strictly to the left of B's bounding box.
- 'left' : '<< %s',
- # The ">>" operator returns true if A's bounding box is strictly to the right of B's bounding box.
- 'right' : '>> %s',
- # The "&<|" operator returns true if A's bounding box overlaps or is below B's bounding box.
- 'overlaps_below' : '&<| %s',
- # The "|&>" operator returns true if A's bounding box overlaps or is above B's bounding box.
- 'overlaps_above' : '|&> %s',
- # The "<<|" operator returns true if A's bounding box is strictly below B's bounding box.
- 'strictly_below' : '<<| %s',
- # The "|>>" operator returns true if A's bounding box is strictly above B's bounding box.
- 'strictly_above' : '|>> %s',
- # The "~=" operator is the "same as" operator. It tests actual geometric equality of two features. So if
- # A and B are the same feature, vertex-by-vertex, the operator returns true.
- 'same_as' : '~= %s',
- 'exact' : '~= %s',
- # The "@" operator returns true if A's bounding box is completely contained by B's bounding box.
- 'contained' : '@ %s',
- # The "~" operator returns true if A's bounding box completely contains B's bounding box.
- 'bbcontains' : '~ %s',
- # The "&&" operator is the "overlaps" operator. If A's bounding boux overlaps B's bounding box the
- # operator returns true.
- 'bboverlaps' : '&& %s',
- }
-
-# PostGIS Geometry Functions -- most of these use GEOS.
-POSTGIS_GEOMETRY_FUNCTIONS = {
- #'distance' : 'Distance', -- doesn't work right now.
- 'equals' : 'Equals',
- 'disjoint' : 'Disjoint',
- 'touches' : 'Touches',
- 'crosses' : 'Crosses',
- 'within' : 'Within',
- 'overlaps' : 'Overlaps',
- 'contains' : 'Contains',
- 'intersects' : 'Intersects',
- 'relate' : 'Relate',
- }
-
-# Any other lookup types that do not require a mapping.
-MISC_TERMS = ['isnull']
-
-# The quotation used for postgis (uses single quotes).
-def quotename(value, dbl=False):
- if dbl: return '"%s"' % value
- else: return "'%s'" % value
-
-# These are the PostGIS-customized QUERY_TERMS, combines both the operators
-# and the geometry functions.
-POSTGIS_TERMS = list(POSTGIS_OPERATORS.keys()) # Getting the operators first
-POSTGIS_TERMS += list(POSTGIS_GEOMETRY_FUNCTIONS.keys()) # Adding on the Geometry Functions
-POSTGIS_TERMS += MISC_TERMS # Adding any other miscellaneous terms (e.g., 'isnull')
-POSTGIS_TERMS = tuple(POSTGIS_TERMS) # Making immutable
-
-def get_geo_where_clause(lookup_type, table_prefix, field_name, value):
- if table_prefix.endswith('.'):
- table_prefix = backend.quote_name(table_prefix[:-1])+'.'
- field_name = backend.quote_name(field_name)
-
- # See if a PostGIS operator matches the lookup type first
- try:
- return '%s%s %s' % (table_prefix, field_name, (POSTGIS_OPERATORS[lookup_type] % '%s'))
- except KeyError:
- pass
-
- # See if a PostGIS Geometry function matches the lookup type next
- try:
- return '%s(%s%s, %%s)' % (POSTGIS_GEOMETRY_FUNCTIONS[lookup_type], table_prefix, field_name)
- except KeyError:
- pass
-
- # For any other lookup type
- if lookup_type == 'isnull':
- return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or ''))
-
- raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type)
+if settings.DATABASE_ENGINE == 'postgresql_psycopg2':
+ # PostGIS is the spatial database, getting the rquired modules, renaming as necessary.
+ from postgis import \
+ PostGISField as GeoBackendField, \
+ POSTGIS_TERMS as GIS_TERMS, \
+ create_spatial_db, get_geo_where_clause
+else:
+ raise NotImplementedError, 'No Geographic Backend exists for %s' % settings.DATABASE_NAME
#### query.py overloaded functions ####
# parse_lookup() and lookup_inner() are modified from their django/db/models/query.py
@@ -130,7 +67,7 @@ def parse_lookup(kwarg_items, opts):
if lookup_type == 'pk':
lookup_type = 'exact'
path.append(None)
- elif len(path) == 0 or not ((lookup_type in QUERY_TERMS) or (lookup_type in POSTGIS_TERMS)):
+ elif len(path) == 0 or not ((lookup_type in QUERY_TERMS) or (lookup_type in GIS_TERMS)):
path.append(lookup_type)
lookup_type = 'exact'
diff --git a/django/contrib/gis/db/backend/postgis/__init__.py b/django/contrib/gis/db/backend/postgis/__init__.py
new file mode 100644
index 0000000000..0564ad7348
--- /dev/null
+++ b/django/contrib/gis/db/backend/postgis/__init__.py
@@ -0,0 +1,7 @@
+"""
+ The PostGIS spatial database backend module.
+"""
+from query import get_geo_where_clause, GEOM_FUNC_PREFIX, POSTGIS_TERMS
+from creation import create_spatial_db
+from field import PostGISField
+
diff --git a/django/contrib/gis/utils/spatial_db.py b/django/contrib/gis/db/backend/postgis/creation.py
index 0fa618b4df..0fa618b4df 100644
--- a/django/contrib/gis/utils/spatial_db.py
+++ b/django/contrib/gis/db/backend/postgis/creation.py
diff --git a/django/contrib/gis/db/backend/postgis/field.py b/django/contrib/gis/db/backend/postgis/field.py
new file mode 100644
index 0000000000..09bc4e642b
--- /dev/null
+++ b/django/contrib/gis/db/backend/postgis/field.py
@@ -0,0 +1,107 @@
+from django.db.models.fields import Field # Django base Field class
+from django.contrib.gis.geos import GEOSGeometry, GEOSException
+from types import StringType
+from query import POSTGIS_TERMS, quotename
+
+class PostGISField(Field):
+ def _add_geom(self, style, db_table):
+ """Constructs the addition of the geometry to the table using the
+ AddGeometryColumn(...) PostGIS (and OGC standard) stored procedure.
+
+ Takes the style object (provides syntax highlighting) and the
+ 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_FIELD(str(self._srid)) + ', ' + \
+ style.SQL_COLTYPE(quotename(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_KEYWORD(' ALTER ') + \
+ style.SQL_FIELD(quotename(self.column, dbl=True)) + \
+ style.SQL_KEYWORD(' SET NOT NULL') + ';'
+ return sql
+
+ 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_KEYWORD(' ON ') + \
+ style.SQL_TABLE(quotename(db_table, dbl=True)) + \
+ style.SQL_KEYWORD(' USING ') + \
+ style.SQL_COLTYPE(index_type) + ' ( ' + \
+ style.SQL_FIELD(quotename(self.column, dbl=True)) + ' ' + \
+ style.SQL_KEYWORD(index_opts) + ' );'
+ return sql
+
+ def _post_create_sql(self, style, db_table):
+ """Returns SQL that will be executed after the model has been
+ created. Geometry columns must be added after creation with the
+ PostGIS AddGeometryColumn() function."""
+
+ # Getting the AddGeometryColumn() SQL necessary to create a PostGIS
+ # geometry field.
+ post_sql = self._add_geom(style, db_table)
+
+ # If the user wants to index this data, then get the indexing SQL as well.
+ if self._index:
+ return '%s\n%s' % (post_sql, self._geom_index(style, db_table))
+ else:
+ return post_sql
+
+ 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)) + ');'
+ return sql
+
+ def get_db_prep_lookup(self, lookup_type, value):
+ "Returns field's value prepared for database lookup, accepts WKT and 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.
+ 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):
+ "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'
diff --git a/django/contrib/gis/db/backend/postgis/management.py b/django/contrib/gis/db/backend/postgis/management.py
new file mode 100644
index 0000000000..33ff44066f
--- /dev/null
+++ b/django/contrib/gis/db/backend/postgis/management.py
@@ -0,0 +1,36 @@
+"""
+ This utility module is for obtaining information about the PostGIS installation.
+
+ See PostGIS docs at Ch. 6.2.1 for more information on these functions.
+"""
+
+def _get_postgis_func(func):
+ "Helper routine for calling PostGIS functions and returning their result."
+ from django.db import connection
+ cursor = connection.cursor()
+ cursor.execute('SELECT %s()' % func)
+ row = cursor.fetchone()
+ cursor.close()
+ return row[0]
+
+def postgis_geos_version():
+ "Returns the version of the GEOS library used with PostGIS."
+ return _get_postgis_func('postgis_geos_version')
+
+def postgis_lib_version():
+ "Returns the version number of the PostGIS library used with PostgreSQL."
+ return _get_postgis_func('postgis_lib_version')
+
+def postgis_proj_version():
+ "Returns the version of the PROJ.4 library used with PostGIS."
+ return _get_postgis_func('postgis_proj_version')
+
+def postgis_version():
+ "Returns PostGIS version number and compile-time options."
+ return _get_postgis_func('postgis_version')
+
+def postgis_full_version():
+ "Returns PostGIS version number and compile-time options."
+ return _get_postgis_func('postgis_full_version')
+
+
diff --git a/django/contrib/gis/db/backend/postgis/query.py b/django/contrib/gis/db/backend/postgis/query.py
new file mode 100644
index 0000000000..3e80d285f8
--- /dev/null
+++ b/django/contrib/gis/db/backend/postgis/query.py
@@ -0,0 +1,127 @@
+"""
+ This module contains the spatial lookup types, and the get_geo_where_clause()
+ routine for PostGIS.
+"""
+from django.db import backend
+from management import postgis_lib_version
+
+# Getting the PostGIS version
+POSTGIS_VERSION = postgis_lib_version()
+MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2 = map(int, POSTGIS_VERSION.split('.'))
+
+# The supported PostGIS versions.
+# TODO: Confirm tests with PostGIS versions 1.1.x -- should work. Versions <= 1.0.x didn't use GEOS C API.
+if MAJOR_VERSION != 1 or MINOR_VERSION1 <= 1:
+ raise Exception, 'PostGIS version %s not supported.' % POSTGIS_VERSION
+
+# PostGIS-specific operators. The commented descriptions of these
+# operators come from Section 6.2.2 of the official PostGIS documentation.
+POSTGIS_OPERATORS = {
+ # The "&<" operator returns true if A's bounding box overlaps or is to the left of B's bounding box.
+ 'overlaps_left' : '&<',
+ # The "&>" operator returns true if A's bounding box overlaps or is to the right of B's bounding box.
+ 'overlaps_right' : '&>',
+ # The "<<" operator returns true if A's bounding box is strictly to the left of B's bounding box.
+ 'left' : '<<',
+ # The ">>" operator returns true if A's bounding box is strictly to the right of B's bounding box.
+ 'right' : '>>',
+ # The "&<|" operator returns true if A's bounding box overlaps or is below B's bounding box.
+ 'overlaps_below' : '&<|',
+ # The "|&>" operator returns true if A's bounding box overlaps or is above B's bounding box.
+ 'overlaps_above' : '|&>',
+ # The "<<|" operator returns true if A's bounding box is strictly below B's bounding box.
+ 'strictly_below' : '<<|',
+ # The "|>>" operator returns true if A's bounding box is strictly above B's bounding box.
+ 'strictly_above' : '|>>',
+ # The "~=" operator is the "same as" operator. It tests actual geometric equality of two features. So if
+ # A and B are the same feature, vertex-by-vertex, the operator returns true.
+ 'same_as' : '~=',
+ 'exact' : '~=',
+ # The "@" operator returns true if A's bounding box is completely contained by B's bounding box.
+ 'contained' : '@',
+ # The "~" operator returns true if A's bounding box completely contains B's bounding box.
+ 'bbcontains' : '~',
+ # The "&&" operator is the "overlaps" operator. If A's bounding boux overlaps B's bounding box the
+ # operator returns true.
+ 'bboverlaps' : '&&',
+ }
+
+# PostGIS Geometry Relationship Functions -- most of these use GEOS.
+#
+# For PostGIS >= 1.2.2 these routines will do a bounding box query first before calling
+# the more expensive GEOS routines (called 'inline index magic').
+#
+POSTGIS_GEOMETRY_FUNCTIONS = {
+ 'equals' : '%sEquals',
+ 'disjoint' : '%sDisjoint',
+ 'touches' : '%sTouches',
+ 'crosses' : '%sCrosses',
+ 'within' : '%sWithin',
+ 'overlaps' : '%sOverlaps',
+ 'contains' : '%sContains',
+ 'intersects' : '%sIntersects',
+ 'relate' : ('%sRelate', str),
+ }
+
+# Versions of PostGIS >= 1.2.2 changed their naming convention to be 'SQL-MM-centric'.
+# Practically, this means that 'ST_' is appended to geometry function names.
+if MINOR_VERSION1 >= 2 and MINOR_VERSION2 >= 2:
+ # The ST_DWithin, ST_CoveredBy, and ST_Covers routines become available in 1.2.2.
+ POSTGIS_GEOMETRY_FUNCTIONS.update(
+ {'dwithin' : ('%sDWithin', float),
+ 'coveredby' : '%sCoveredBy',
+ 'covers' : '%sCovers',
+ }
+ )
+ GEOM_FUNC_PREFIX = 'ST_'
+else:
+ GEOM_FUNC_PREFIX = ''
+
+# Updating with the geometry function prefix.
+for k, v in POSTGIS_GEOMETRY_FUNCTIONS.items():
+ if isinstance(v, tuple):
+ v = list(v)
+ v[0] = v[0] % GEOM_FUNC_PREFIX
+ v = tuple(v)
+ else:
+ v = v % GEOM_FUNC_PREFIX
+ POSTGIS_GEOMETRY_FUNCTIONS[k] = v
+
+# Any other lookup types that do not require a mapping.
+MISC_TERMS = ['isnull']
+
+# The quotation used for postgis (uses single quotes).
+def quotename(value, dbl=False):
+ if dbl: return '"%s"' % value
+ else: return "'%s'" % value
+
+# These are the PostGIS-customized QUERY_TERMS -- a list of the lookup types
+# allowed for geographic queries.
+POSTGIS_TERMS = list(POSTGIS_OPERATORS.keys()) # Getting the operators first
+POSTGIS_TERMS += list(POSTGIS_GEOMETRY_FUNCTIONS.keys()) # Adding on the Geometry Functions
+POSTGIS_TERMS += MISC_TERMS # Adding any other miscellaneous terms (e.g., 'isnull')
+POSTGIS_TERMS = tuple(POSTGIS_TERMS) # Making immutable
+
+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 = backend.quote_name(table_prefix[:-1])+'.'
+ field_name = backend.quote_name(field_name)
+
+ # See if a PostGIS operator matches the lookup type first
+ try:
+ 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:
+ return '%s(%s%s, %%s)' % (POSTGIS_GEOMETRY_FUNCTIONS[lookup_type], table_prefix, field_name)
+ except KeyError:
+ pass
+
+ # Handling 'isnull' lookup type
+ if lookup_type == 'isnull':
+ return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or ''))
+
+ raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type)
diff --git a/django/contrib/gis/db/models/fields/__init__.py b/django/contrib/gis/db/models/fields/__init__.py
index d27208dffe..e004d3bbea 100644
--- a/django/contrib/gis/db/models/fields/__init__.py
+++ b/django/contrib/gis/db/models/fields/__init__.py
@@ -1,15 +1,10 @@
-# The Django base Field class.
-from django.db.models.fields import Field
+from django.contrib.gis.db.backend import GeoBackendField # depends on the spatial database backend.
from django.contrib.gis.db.models.proxy import GeometryProxy
-from django.contrib.gis.db.models.postgis import POSTGIS_TERMS, quotename
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.
-
-class GeometryField(Field):
+class GeometryField(GeoBackendField):
"The base GIS field -- maps to the OpenGIS Specification Geometry type."
# The OpenGIS Geometry name.
@@ -33,67 +28,6 @@ class GeometryField(Field):
self._dim = dim
super(GeometryField, self).__init__(**kwargs) # Calling the parent initializtion function
- def _add_geom(self, style, db_table):
- """Constructs the addition of the geometry to the table using the
- AddGeometryColumn(...) PostGIS (and OGC standard) stored procedure.
-
- Takes the style object (provides syntax highlighting) and the
- 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_FIELD(str(self._srid)) + ', ' + \
- style.SQL_COLTYPE(quotename(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_KEYWORD(' ALTER ') + \
- style.SQL_FIELD(quotename(self.column, dbl=True)) + \
- style.SQL_KEYWORD(' SET NOT NULL') + ';'
- return sql
-
- 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_KEYWORD(' ON ') + \
- style.SQL_TABLE(quotename(db_table, dbl=True)) + \
- style.SQL_KEYWORD(' USING ') + \
- style.SQL_COLTYPE(index_type) + ' ( ' + \
- style.SQL_FIELD(quotename(self.column, dbl=True)) + ' ' + \
- style.SQL_KEYWORD(index_opts) + ' );'
- return sql
-
- def _post_create_sql(self, style, db_table):
- """Returns SQL that will be executed after the model has been
- created. Geometry columns must be added after creation with the
- PostGIS AddGeometryColumn() function."""
-
- # Getting the AddGeometryColumn() SQL necessary to create a PostGIS
- # geometry field.
- post_sql = self._add_geom(style, db_table)
-
- # If the user wants to index this data, then get the indexing SQL as well.
- if self._index:
- return '%s\n%s' % (post_sql, self._geom_index(style, db_table))
- else:
- return post_sql
-
- 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)) + ');'
- return sql
-
def contribute_to_class(self, cls, name):
super(GeometryField, self).contribute_to_class(cls, name)
@@ -112,47 +46,6 @@ class GeometryField(Field):
def get_internal_type(self):
return "NoField"
- def get_db_prep_lookup(self, lookup_type, value):
- "Returns field's value prepared for database lookup, accepts WKT and 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.
- 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):
- "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]
diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py
index 6619e54c9a..dab1f04eb6 100644
--- a/django/contrib/gis/db/models/query.py
+++ b/django/contrib/gis/db/models/query.py
@@ -1,7 +1,7 @@
from django.db.models.query import Q, QuerySet
from django.db import backend
from django.contrib.gis.db.models.fields import GeometryField
-from django.contrib.gis.db.models.postgis import parse_lookup
+from django.contrib.gis.db.backend import parse_lookup # parse_lookup depends on the spatial database backend.
from django.db.models.fields import FieldDoesNotExist
import operator
diff --git a/django/contrib/gis/tests/__init__.py b/django/contrib/gis/tests/__init__.py
index fb4167fe22..fc9bd6cb03 100644
--- a/django/contrib/gis/tests/__init__.py
+++ b/django/contrib/gis/tests/__init__.py
@@ -1,6 +1,6 @@
from copy import copy
from unittest import TestSuite, TextTestRunner
-from django.contrib.gis.utils import create_spatial_db
+from django.contrib.gis.db.backend import create_spatial_db
from django.db import connection
from django.test.utils import destroy_test_db
diff --git a/django/contrib/gis/tests/geoapp/tests.py b/django/contrib/gis/tests/geoapp/tests.py
index 50a21aa227..dcc5e681ff 100644
--- a/django/contrib/gis/tests/geoapp/tests.py
+++ b/django/contrib/gis/tests/geoapp/tests.py
@@ -91,7 +91,7 @@ class GeoModelTest(unittest.TestCase):
nmi.save()
def test005_left_right(self):
- "Testing the left ('<<') right ('>>') operators."
+ "Testing the 'left' and 'right' lookup types."
# Left: A << B => true if xmax(A) < xmin(B)
# Right: A >> B => true if xmin(A) > xmax(B)