Commit 26996e2d authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #24499 -- Dropped support for PostGIS 1.5.

parent faad6070
Loading
Loading
Loading
Loading
+3 −17
Original line number Diff line number Diff line
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
        # Check that postgis extension is installed.
        with self.cursor() as cursor:
            cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")
+0 −10
Original line number Diff line number Diff line
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 ''
+7 −34
Original line number Diff line number Diff line
@@ -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:
+5 −50
Original line number Diff line number Diff line
@@ -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),
                    }
                )

        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),
                }
            )
+2 −2
Original line number Diff line number Diff line
@@ -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
Loading