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:
@@ -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")
|
||||
|
||||
@@ -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 ''
|
||||
@@ -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:
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user