From 91ef2a5253a50a602523bdda943c32c4cfe719fe Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Sat, 6 Oct 2012 09:57:24 -0700 Subject: [PATCH] Use native geometry types on PostGIS 2.0+ instead of `AddGeometryColumn` and don't query database in `PostGISCreation.sql_table_creation_suffix`. --- django/contrib/gis/db/backends/base.py | 3 +- .../gis/db/backends/postgis/creation.py | 32 +++++++------------ .../gis/db/backends/postgis/operations.py | 23 ++++++++++--- django/contrib/gis/db/models/fields.py | 2 +- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/django/contrib/gis/db/backends/base.py b/django/contrib/gis/db/backends/base.py index 0bd598997cb..171a304439c 100644 --- a/django/contrib/gis/db/backends/base.py +++ b/django/contrib/gis/db/backends/base.py @@ -32,8 +32,9 @@ class BaseSpatialOperations(object): # How the geometry column should be selected. select = None - # Does the spatial database have a geography type? + # Does the spatial database have a geometry or geography type? geography = False + geometry = False area = False centroid = False diff --git a/django/contrib/gis/db/backends/postgis/creation.py b/django/contrib/gis/db/backends/postgis/creation.py index 06b60117f69..406dc4e487b 100644 --- a/django/contrib/gis/db/backends/postgis/creation.py +++ b/django/contrib/gis/db/backends/postgis/creation.py @@ -4,7 +4,8 @@ from django.db.backends.postgresql_psycopg2.creation import DatabaseCreation class PostGISCreation(DatabaseCreation): geom_index_type = 'GIST' - geom_index_opts = 'GIST_GEOMETRY_OPS' + geom_index_ops = 'GIST_GEOMETRY_OPS' + geom_index_ops_nd = 'GIST_GEOMETRY_OPS_ND' def sql_indexes_for_field(self, model, f, style): "Return any spatial index creation SQL for the field." @@ -17,8 +18,9 @@ class PostGISCreation(DatabaseCreation): qn = self.connection.ops.quote_name db_table = model._meta.db_table - if f.geography: - # Geogrophy columns are created normally. + if f.geography or self.connection.ops.geometry: + # Geography and Geometry (PostGIS 2.0+) columns are + # created normally. pass else: # Geometry columns are created by `AddGeometryColumn` @@ -47,33 +49,23 @@ class PostGISCreation(DatabaseCreation): # which are fast on multidimensional cases, or just plain # gist index for the 2d case. if f.geography: - index_opts = '' - elif self.connection.ops.spatial_version >= (2, 0): + index_ops = '' + elif self.connection.ops.geometry: if f.dim > 2: - index_opts = ' ' + style.SQL_KEYWORD('gist_geometry_ops_nd') + index_ops = ' ' + style.SQL_KEYWORD(self.geom_index_ops_nd) else: - index_opts = '' + index_ops = '' else: - index_opts = ' ' + style.SQL_KEYWORD(self.geom_index_opts) + index_ops = ' ' + style.SQL_KEYWORD(self.geom_index_ops) output.append(style.SQL_KEYWORD('CREATE INDEX ') + style.SQL_TABLE(qn('%s_%s_id' % (db_table, f.column))) + style.SQL_KEYWORD(' ON ') + style.SQL_TABLE(qn(db_table)) + style.SQL_KEYWORD(' USING ') + style.SQL_COLTYPE(self.geom_index_type) + ' ( ' + - style.SQL_FIELD(qn(f.column)) + index_opts + ' );') + style.SQL_FIELD(qn(f.column)) + index_ops + ' );') return output def sql_table_creation_suffix(self): - cursor = self.connection.cursor() - cursor.execute('SELECT datname FROM pg_database;') - db_names = [row[0] for row in cursor.fetchall()] postgis_template = getattr(settings, 'POSTGIS_TEMPLATE', 'template_postgis') - - if postgis_template in db_names: - qn = self.connection.ops.quote_name - return ' TEMPLATE %s' % qn(postgis_template) - elif self.connection.ops.spatial_version < (2, 0): - raise ImproperlyConfigured("Template database '%s' does not exist." % postgis_template) - else: - return '' + return ' TEMPLATE %s' % self.connection.ops.quote_name(postgis_template) diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py index ff9110de01c..aa23b974dbb 100644 --- a/django/contrib/gis/db/backends/postgis/operations.py +++ b/django/contrib/gis/db/backends/postgis/operations.py @@ -103,11 +103,12 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations): self.geom_func_prefix = prefix self.spatial_version = version except DatabaseError: - raise ImproperlyConfigured('Cannot determine PostGIS version for database "%s". ' - 'GeoDjango requires at least PostGIS version 1.3. ' - 'Was the database created from a spatial database ' - 'template?' % self.connection.settings_dict['NAME'] - ) + raise ImproperlyConfigured( + 'Cannot determine PostGIS version for database "%s". ' + 'GeoDjango requires at least PostGIS version 1.3. ' + 'Was the database created from a spatial database ' + 'template?' % self.connection.settings_dict['NAME'] + ) # TODO: Raise helpful exceptions as they become known. # PostGIS-specific operators. The commented descriptions of these @@ -215,6 +216,10 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations): 'bboverlaps' : PostGISOperator('&&'), } + # Native geometry type support added in PostGIS 2.0. + if version >= (2, 0, 0): + self.geometry = True + # Creating a dictionary lookup of all GIS terms for PostGIS. gis_terms = ['isnull'] gis_terms += list(self.geometry_operators) @@ -320,6 +325,14 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations): 'only with an SRID of 4326.') return 'geography(%s,%d)'% (f.geom_type, f.srid) + elif self.geometry: + # Postgis 2.0 supports type-based geometries. + # TODO: Support 'M' extension. + if f.dim == 3: + geom_type = f.geom_type + 'Z' + else: + geom_type = f.geom_type + return 'geometry(%s,%d)' % (geom_type, f.srid) else: return None diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py index c8b8901d596..d90ce309d46 100644 --- a/django/contrib/gis/db/models/fields.py +++ b/django/contrib/gis/db/models/fields.py @@ -95,7 +95,7 @@ class GeometryField(Field): # Is this a geography rather than a geometry column? self.geography = geography - # Oracle-specific private attributes for creating the entrie in + # Oracle-specific private attributes for creating the entry in # `USER_SDO_GEOM_METADATA` self._extent = kwargs.pop('extent', (-180.0, -90.0, 180.0, 90.0)) self._tolerance = kwargs.pop('tolerance', 0.05)