1
0
mirror of https://github.com/django/django.git synced 2025-10-24 14:16:09 +00:00

Fixed #24499 -- Dropped support for PostGIS 1.5.

This commit is contained in:
Tim Graham
2015-03-17 11:16:50 -04:00
parent faad6070ee
commit 26996e2d55
13 changed files with 26 additions and 273 deletions

View File

@@ -1,10 +1,7 @@
from django.conf import settings
from django.db.backends.base.base import NO_DB_ALIAS
from django.db.backends.postgresql_psycopg2.base import \
DatabaseWrapper as Psycopg2DatabaseWrapper
from django.utils.functional import cached_property
from .creation import PostGISCreation
from .features import DatabaseFeatures
from .introspection import PostGISIntrospection
from .operations import PostGISOperations
@@ -18,22 +15,11 @@ class DatabaseWrapper(Psycopg2DatabaseWrapper):
super(DatabaseWrapper, self).__init__(*args, **kwargs)
if kwargs.get('alias', '') != NO_DB_ALIAS:
self.features = DatabaseFeatures(self)
self.creation = PostGISCreation(self)
self.ops = PostGISOperations(self)
self.introspection = PostGISIntrospection(self)
@cached_property
def template_postgis(self):
template_postgis = getattr(settings, 'POSTGIS_TEMPLATE', 'template_postgis')
with self._nodb_connection.cursor() as cursor:
cursor.execute('SELECT 1 FROM pg_database WHERE datname = %s LIMIT 1;', (template_postgis,))
if cursor.fetchone():
return template_postgis
return None
def prepare_database(self):
super(DatabaseWrapper, self).prepare_database()
if self.template_postgis is None:
# Check that postgis extension is installed on PostGIS >= 2
with self.cursor() as cursor:
cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")
# Check that postgis extension is installed.
with self.cursor() as cursor:
cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")

View File

@@ -1,10 +0,0 @@
from django.db.backends.postgresql_psycopg2.creation import DatabaseCreation
class PostGISCreation(DatabaseCreation):
def sql_table_creation_suffix(self):
if self.connection.template_postgis is not None:
return ' TEMPLATE %s' % (
self.connection.ops.quote_name(self.connection.template_postgis),)
return ''

View File

@@ -110,6 +110,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
self.distance_spheroid = prefix + 'distance_spheroid'
self.envelope = prefix + 'Envelope'
self.extent = prefix + 'Extent'
self.extent3d = prefix + '3DExtent'
self.force_rhr = prefix + 'ForceRHR'
self.geohash = prefix + 'GeoHash'
self.geojson = prefix + 'AsGeoJson'
@@ -117,12 +118,14 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
self.intersection = prefix + 'Intersection'
self.kml = prefix + 'AsKML'
self.length = prefix + 'Length'
self.length3d = prefix + '3DLength'
self.length_spheroid = prefix + 'length_spheroid'
self.makeline = prefix + 'MakeLine'
self.mem_size = prefix + 'mem_size'
self.num_geom = prefix + 'NumGeometries'
self.num_points = prefix + 'npoints'
self.perimeter = prefix + 'Perimeter'
self.perimeter3d = prefix + '3DPerimeter'
self.point_on_surface = prefix + 'PointOnSurface'
self.polygonize = prefix + 'Polygonize'
self.reverse = prefix + 'Reverse'
@@ -135,34 +138,6 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
self.union = prefix + 'Union'
self.unionagg = prefix + 'Union'
# Following "attributes" are properties due to the spatial_version check and
# to delay database access
@property
def extent3d(self):
if self.spatial_version >= (2, 0, 0):
return self.geom_func_prefix + '3DExtent'
else:
return self.geom_func_prefix + 'Extent3D'
@property
def length3d(self):
if self.spatial_version >= (2, 0, 0):
return self.geom_func_prefix + '3DLength'
else:
return self.geom_func_prefix + 'Length3D'
@property
def perimeter3d(self):
if self.spatial_version >= (2, 0, 0):
return self.geom_func_prefix + '3DPerimeter'
else:
return self.geom_func_prefix + 'Perimeter3D'
@property
def geometry(self):
# Native geometry type support added in PostGIS 2.0.
return self.spatial_version >= (2, 0, 0)
@cached_property
def spatial_version(self):
"""Determine the version of the PostGIS library."""
@@ -180,7 +155,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
except ProgrammingError:
raise ImproperlyConfigured(
'Cannot determine PostGIS version for database "%s". '
'GeoDjango requires at least PostGIS version 1.5. '
'GeoDjango requires at least PostGIS version 2.0. '
'Was the database created from a spatial database '
'template?' % self.connection.settings_dict['NAME']
)
@@ -234,16 +209,14 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
raise NotImplementedError('PostGIS only supports geography columns with an SRID of 4326.')
return 'geography(%s,%d)' % (f.geom_type, f.srid)
elif self.geometry:
# Postgis 2.0 supports type-based geometries.
else:
# 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
def get_distance(self, f, dist_val, lookup_type):
"""
@@ -253,7 +226,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
This is the most complex implementation of the spatial backends due to
what is supported on geodetic geometry columns vs. what's available on
projected geometry columns. In addition, it has to take into account
the geography column type newly introduced in PostGIS 1.5.
the geography column type.
"""
# Getting the distance parameter and any options.
if len(dist_val) == 1:

View File

@@ -3,12 +3,8 @@ from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
class PostGISSchemaEditor(DatabaseSchemaEditor):
geom_index_type = 'GIST'
geom_index_ops = 'GIST_GEOMETRY_OPS'
geom_index_ops_nd = 'GIST_GEOMETRY_OPS_ND'
sql_add_geometry_column = "SELECT AddGeometryColumn(%(table)s, %(column)s, %(srid)s, %(geom_type)s, %(dim)s)"
sql_drop_geometry_column = "SELECT DropGeometryColumn(%(table)s, %(column)s)"
sql_alter_geometry_column_not_null = "ALTER TABLE %(table)s ALTER COLUMN %(column)s SET NOT NULL"
sql_add_spatial_index = "CREATE INDEX %(index)s ON %(table)s USING %(index_type)s (%(column)s %(ops)s)"
sql_clear_geometry_columns = "DELETE FROM geometry_columns WHERE f_table_name = %(table)s"
@@ -24,48 +20,21 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
if not isinstance(field, GeometryField):
return super(PostGISSchemaEditor, self).column_sql(model, field, include_default)
if field.geography or self.connection.ops.geometry:
# Geography and Geometry (PostGIS 2.0+) columns are
# created normally.
column_sql = super(PostGISSchemaEditor, self).column_sql(model, field, include_default)
else:
column_sql = None, None
# Geometry columns are created by the `AddGeometryColumn`
# stored procedure.
self.geometry_sql.append(
self.sql_add_geometry_column % {
"table": self.geo_quote_name(model._meta.db_table),
"column": self.geo_quote_name(field.column),
"srid": field.srid,
"geom_type": self.geo_quote_name(field.geom_type),
"dim": field.dim,
}
)
if not field.null:
self.geometry_sql.append(
self.sql_alter_geometry_column_not_null % {
"table": self.quote_name(model._meta.db_table),
"column": self.quote_name(field.column),
}
)
column_sql = super(PostGISSchemaEditor, self).column_sql(model, field, include_default)
if field.spatial_index:
# Spatial indexes created the same way for both Geometry and
# Geography columns.
# PostGIS 2.0 does not support GIST_GEOMETRY_OPS. So, on 1.5
# we use GIST_GEOMETRY_OPS, on 2.0 we use either "nd" ops
# which are fast on multidimensional cases, or just plain
# gist index for the 2d case.
if field.geography:
index_ops = ''
elif self.connection.ops.geometry:
else:
# Use either "nd" ops which are fast on multidimensional cases
# or just plain gist index for the 2d case.
if field.dim > 2:
index_ops = self.geom_index_ops_nd
else:
index_ops = ''
else:
index_ops = self.geom_index_ops
self.geometry_sql.append(
self.sql_add_spatial_index % {
"index": self.quote_name('%s_%s_id' % (model._meta.db_table, field.column)),
@@ -96,17 +65,3 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
for sql in self.geometry_sql:
self.execute(sql)
self.geometry_sql = []
def remove_field(self, model, field):
from django.contrib.gis.db.models.fields import GeometryField
if not isinstance(field, GeometryField) or \
self.connection.ops.spatial_version > (2, 0) or \
field.geography:
super(PostGISSchemaEditor, self).remove_field(model, field)
else:
self.execute(
self.sql_drop_geometry_column % {
"table": self.geo_quote_name(model._meta.db_table),
"column": self.geo_quote_name(field.column),
}
)

View File

@@ -462,8 +462,8 @@ class BaseDatabaseSchemaEditor(object):
(new_type is None and new_field.remote_field is None)):
raise ValueError(
"Cannot alter field %s into %s - they do not properly define "
"db_type (are you using PostGIS 1.5 or badly-written custom "
"fields?)" % (old_field, new_field),
"db_type (are you using a badly-written custom field?)" %
(old_field, new_field),
)
elif old_type is None and new_type is None and (
old_field.remote_field.through and new_field.remote_field.through and