Fixed #27056 -- Allowed migrating geometry field dimension on PostGIS
Thanks Tim Graham for the review.
This commit is contained in:
parent
8e2ac3bcaf
commit
92323d54fd
|
@ -6,6 +6,9 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
|
||||||
geom_index_ops_nd = 'GIST_GEOMETRY_OPS_ND'
|
geom_index_ops_nd = 'GIST_GEOMETRY_OPS_ND'
|
||||||
rast_index_wrapper = 'ST_ConvexHull(%s)'
|
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):
|
def geo_quote_name(self, name):
|
||||||
return self.connection.ops.geo_quote_name(name)
|
return self.connection.ops.geo_quote_name(name)
|
||||||
|
|
||||||
|
@ -36,3 +39,29 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
|
||||||
"columns": field_column,
|
"columns": field_column,
|
||||||
"extra": '',
|
"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,
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
|
@ -141,6 +141,8 @@ Minor features
|
||||||
``https://cdnjs.cloudflare.com`` which is more suitable for production use
|
``https://cdnjs.cloudflare.com`` which is more suitable for production use
|
||||||
than the the old ``http://openlayers.org`` source.
|
than the the old ``http://openlayers.org`` source.
|
||||||
|
|
||||||
|
* PostGIS migrations can now change field dimensions.
|
||||||
|
|
||||||
:mod:`django.contrib.messages`
|
:mod:`django.contrib.messages`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from unittest import skipIf
|
||||||
|
|
||||||
from django.contrib.gis.db.models import fields
|
from django.contrib.gis.db.models import fields
|
||||||
|
from django.contrib.gis.geos import MultiPolygon, Polygon
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import connection, migrations, models
|
from django.db import connection, migrations, models
|
||||||
from django.db.migrations.migration import Migration
|
from django.db.migrations.migration import Migration
|
||||||
|
@ -9,7 +12,7 @@ from django.test import (
|
||||||
TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature,
|
TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ..utils import mysql
|
from ..utils import mysql, spatialite
|
||||||
|
|
||||||
if connection.features.gis_enabled:
|
if connection.features.gis_enabled:
|
||||||
try:
|
try:
|
||||||
|
@ -59,7 +62,7 @@ class OperationTestCase(TransactionTestCase):
|
||||||
('geom', fields.MultiPolygonField(srid=4326))
|
('geom', fields.MultiPolygonField(srid=4326))
|
||||||
]
|
]
|
||||||
if connection.features.supports_raster or force_raster_creation:
|
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)]
|
operations = [migrations.CreateModel('Neighborhood', test_fields)]
|
||||||
self.current_state = self.apply_operations('gis', ProjectState(), operations)
|
self.current_state = self.apply_operations('gis', ProjectState(), operations)
|
||||||
|
|
||||||
|
@ -187,6 +190,25 @@ class OperationTests(OperationTestCase):
|
||||||
if connection.features.supports_raster:
|
if connection.features.supports_raster:
|
||||||
self.assertSpatialIndexExists('gis_neighborhood', 'rast', raster=True)
|
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')
|
@skipIfDBFeature('supports_raster')
|
||||||
class NoRasterSupportTests(OperationTestCase):
|
class NoRasterSupportTests(OperationTestCase):
|
||||||
|
|
Loading…
Reference in New Issue