summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2016-09-19 09:58:58 +0200
committerClaude Paroz <claude@2xlibre.net>2016-09-22 16:40:27 +0200
commit92323d54fd6df077dc523c423c7bb2dd8dbde621 (patch)
tree62db1a11c37845671b534707fb2872cda9dee2aa
parent8e2ac3bcafb34e4f10be20f24e37319522459095 (diff)
Fixed #27056 -- Allowed migrating geometry field dimension on PostGIS
Thanks Tim Graham for the review.
-rw-r--r--django/contrib/gis/db/backends/postgis/schema.py29
-rw-r--r--docs/releases/1.11.txt2
-rw-r--r--tests/gis_tests/gis_migrations/test_operations.py26
3 files changed, 55 insertions, 2 deletions
diff --git a/django/contrib/gis/db/backends/postgis/schema.py b/django/contrib/gis/db/backends/postgis/schema.py
index 4ee46cb3ff..d88901b50d 100644
--- a/django/contrib/gis/db/backends/postgis/schema.py
+++ b/django/contrib/gis/db/backends/postgis/schema.py
@@ -6,6 +6,9 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
geom_index_ops_nd = 'GIST_GEOMETRY_OPS_ND'
rast_index_wrapper = 'ST_ConvexHull(%s)'
+ sql_alter_column_to_3d = "ALTER COLUMN %(column)s TYPE %(type)s USING ST_Force3D(%(column)s)::%(type)s"
+ sql_alter_column_to_2d = "ALTER COLUMN %(column)s TYPE %(type)s USING ST_Force2D(%(column)s)::%(type)s"
+
def geo_quote_name(self, name):
return self.connection.ops.geo_quote_name(name)
@@ -36,3 +39,29 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
"columns": field_column,
"extra": '',
}
+
+ def _alter_column_type_sql(self, table, old_field, new_field, new_type):
+ """
+ Special case when dimension changed.
+ """
+ if not hasattr(old_field, 'dim') or not hasattr(new_field, 'dim'):
+ return super(PostGISSchemaEditor, self)._alter_column_type_sql(
+ table, old_field, new_field, new_type
+ )
+
+ if old_field.dim == 2 and new_field.dim == 3:
+ sql_alter = self.sql_alter_column_to_3d
+ elif old_field.dim == 3 and new_field.dim == 2:
+ sql_alter = self.sql_alter_column_to_2d
+ else:
+ sql_alter = self.sql_alter_column_type
+ return (
+ (
+ sql_alter % {
+ "column": self.quote_name(new_field.column),
+ "type": new_type,
+ },
+ [],
+ ),
+ [],
+ )
diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt
index 75407ceed8..73240c76ac 100644
--- a/docs/releases/1.11.txt
+++ b/docs/releases/1.11.txt
@@ -141,6 +141,8 @@ Minor features
``https://cdnjs.cloudflare.com`` which is more suitable for production use
than the the old ``http://openlayers.org`` source.
+* PostGIS migrations can now change field dimensions.
+
:mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/gis_tests/gis_migrations/test_operations.py b/tests/gis_tests/gis_migrations/test_operations.py
index 99dc1295d9..26ff16feed 100644
--- a/tests/gis_tests/gis_migrations/test_operations.py
+++ b/tests/gis_tests/gis_migrations/test_operations.py
@@ -1,6 +1,9 @@
from __future__ import unicode_literals
+from unittest import skipIf
+
from django.contrib.gis.db.models import fields
+from django.contrib.gis.geos import MultiPolygon, Polygon
from django.core.exceptions import ImproperlyConfigured
from django.db import connection, migrations, models
from django.db.migrations.migration import Migration
@@ -9,7 +12,7 @@ from django.test import (
TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature,
)
-from ..utils import mysql
+from ..utils import mysql, spatialite
if connection.features.gis_enabled:
try:
@@ -59,7 +62,7 @@ class OperationTestCase(TransactionTestCase):
('geom', fields.MultiPolygonField(srid=4326))
]
if connection.features.supports_raster or force_raster_creation:
- test_fields += [('rast', fields.RasterField(srid=4326))]
+ test_fields += [('rast', fields.RasterField(srid=4326, null=True))]
operations = [migrations.CreateModel('Neighborhood', test_fields)]
self.current_state = self.apply_operations('gis', ProjectState(), operations)
@@ -187,6 +190,25 @@ class OperationTests(OperationTestCase):
if connection.features.supports_raster:
self.assertSpatialIndexExists('gis_neighborhood', 'rast', raster=True)
+ @skipUnlessDBFeature("supports_3d_storage")
+ @skipIf(spatialite, "Django currently doesn't support altering Spatialite geometry fields")
+ def test_alter_geom_field_dim(self):
+ Neighborhood = self.current_state.apps.get_model('gis', 'Neighborhood')
+ p1 = Polygon(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)))
+ Neighborhood.objects.create(name='TestDim', geom=MultiPolygon(p1, p1))
+ # Add 3rd dimension.
+ self.alter_gis_model(
+ migrations.AlterField, 'Neighborhood', 'geom', False,
+ fields.MultiPolygonField, field_class_kwargs={'srid': 4326, 'dim': 3}
+ )
+ self.assertTrue(Neighborhood.objects.first().geom.hasz)
+ # Rewind to 2 dimensions.
+ self.alter_gis_model(
+ migrations.AlterField, 'Neighborhood', 'geom', False,
+ fields.MultiPolygonField, field_class_kwargs={'srid': 4326, 'dim': 2}
+ )
+ self.assertFalse(Neighborhood.objects.first().geom.hasz)
+
@skipIfDBFeature('supports_raster')
class NoRasterSupportTests(OperationTestCase):