Fixed #29116 -- Fixed OpenLayersWidget deserialization ignoring the widget map's SRID.
Regression in 6ecccad711
.
This commit is contained in:
parent
09c6d01461
commit
2a2ed0e70a
|
@ -35,9 +35,14 @@ class GeometryField(forms.Field):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not isinstance(value, GEOSGeometry):
|
if not isinstance(value, GEOSGeometry):
|
||||||
try:
|
if hasattr(self.widget, 'deserialize'):
|
||||||
value = GEOSGeometry(value)
|
value = self.widget.deserialize(value)
|
||||||
except (GEOSException, ValueError, TypeError):
|
else:
|
||||||
|
try:
|
||||||
|
value = GEOSGeometry(value)
|
||||||
|
except (GEOSException, ValueError, TypeError):
|
||||||
|
value = None
|
||||||
|
if value is None:
|
||||||
raise forms.ValidationError(self.error_messages['invalid_geom'], code='invalid_geom')
|
raise forms.ValidationError(self.error_messages['invalid_geom'], code='invalid_geom')
|
||||||
|
|
||||||
# Try to set the srid
|
# Try to set the srid
|
||||||
|
|
|
@ -2,6 +2,7 @@ import logging
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.gis import gdal
|
from django.contrib.gis import gdal
|
||||||
|
from django.contrib.gis.geometry import json_regex
|
||||||
from django.contrib.gis.geos import GEOSException, GEOSGeometry
|
from django.contrib.gis.geos import GEOSException, GEOSGeometry
|
||||||
from django.forms.widgets import Widget
|
from django.forms.widgets import Widget
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
|
@ -36,7 +37,7 @@ class BaseGeometryWidget(Widget):
|
||||||
def deserialize(self, value):
|
def deserialize(self, value):
|
||||||
try:
|
try:
|
||||||
return GEOSGeometry(value)
|
return GEOSGeometry(value)
|
||||||
except (GEOSException, ValueError) as err:
|
except (GEOSException, ValueError, TypeError) as err:
|
||||||
logger.error("Error creating geometry from value '%s' (%s)", value, err)
|
logger.error("Error creating geometry from value '%s' (%s)", value, err)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -91,6 +92,13 @@ class OpenLayersWidget(BaseGeometryWidget):
|
||||||
def serialize(self, value):
|
def serialize(self, value):
|
||||||
return value.json if value else ''
|
return value.json if value else ''
|
||||||
|
|
||||||
|
def deserialize(self, value):
|
||||||
|
geom = super().deserialize(value)
|
||||||
|
# GeoJSON assumes WGS84 (4326). Use the map's SRID instead.
|
||||||
|
if geom and json_regex.match(value) and self.map_srid != 4326:
|
||||||
|
geom.srid = self.map_srid
|
||||||
|
return geom
|
||||||
|
|
||||||
|
|
||||||
class OSMWidget(OpenLayersWidget):
|
class OSMWidget(OpenLayersWidget):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -29,3 +29,6 @@ Bugfixes
|
||||||
* Fixed a regression in Django 1.11 where an empty choice could be initially
|
* Fixed a regression in Django 1.11 where an empty choice could be initially
|
||||||
selected for the ``SelectMultiple`` and ``CheckboxSelectMultiple`` widgets
|
selected for the ``SelectMultiple`` and ``CheckboxSelectMultiple`` widgets
|
||||||
(:ticket:`29273`).
|
(:ticket:`29273`).
|
||||||
|
|
||||||
|
* Fixed a regression in Django 2.0 where ``OpenLayersWidget`` deserialization
|
||||||
|
ignored the widget map's SRID and assumed 4326 (WGS84) (:ticket:`29116`).
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.contrib.gis import forms
|
from django.contrib.gis import forms
|
||||||
from django.contrib.gis.forms import BaseGeometryWidget
|
from django.contrib.gis.forms import BaseGeometryWidget, OpenLayersWidget
|
||||||
from django.contrib.gis.geos import GEOSGeometry
|
from django.contrib.gis.geos import GEOSGeometry
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
|
@ -31,8 +31,9 @@ class GeometryFieldTest(SimpleTestCase):
|
||||||
fld = forms.GeometryField(srid=32140)
|
fld = forms.GeometryField(srid=32140)
|
||||||
tol = 0.0000001
|
tol = 0.0000001
|
||||||
xform_geom = GEOSGeometry('POINT (951640.547328465 4219369.26171664)', srid=32140)
|
xform_geom = GEOSGeometry('POINT (951640.547328465 4219369.26171664)', srid=32140)
|
||||||
# The cleaned geometry should be transformed to 32140.
|
# The cleaned geometry is transformed to 32140 (the widget map_srid is 3857).
|
||||||
cleaned_geom = fld.clean('SRID=4326;POINT (-95.363151 29.763374)')
|
cleaned_geom = fld.clean('SRID=3857;POINT (-10615777.40976205 3473169.895707852)')
|
||||||
|
self.assertEqual(cleaned_geom.srid, 32140)
|
||||||
self.assertTrue(xform_geom.equals_exact(cleaned_geom, tol))
|
self.assertTrue(xform_geom.equals_exact(cleaned_geom, tol))
|
||||||
|
|
||||||
def test_null(self):
|
def test_null(self):
|
||||||
|
@ -83,6 +84,11 @@ class GeometryFieldTest(SimpleTestCase):
|
||||||
with self.assertRaises(forms.ValidationError):
|
with self.assertRaises(forms.ValidationError):
|
||||||
fld.to_python(wkt)
|
fld.to_python(wkt)
|
||||||
|
|
||||||
|
def test_to_python_different_map_srid(self):
|
||||||
|
f = forms.GeometryField(widget=OpenLayersWidget)
|
||||||
|
json = '{ "type": "Point", "coordinates": [ 5.0, 23.0 ] }'
|
||||||
|
self.assertEqual(GEOSGeometry('POINT(5 23)', srid=f.widget.map_srid), f.to_python(json))
|
||||||
|
|
||||||
def test_field_with_text_widget(self):
|
def test_field_with_text_widget(self):
|
||||||
class PointForm(forms.Form):
|
class PointForm(forms.Form):
|
||||||
pt = forms.PointField(srid=4326, widget=forms.TextInput)
|
pt = forms.PointField(srid=4326, widget=forms.TextInput)
|
||||||
|
@ -91,6 +97,8 @@ class GeometryFieldTest(SimpleTestCase):
|
||||||
cleaned_pt = form.fields['pt'].clean('POINT(5 23)')
|
cleaned_pt = form.fields['pt'].clean('POINT(5 23)')
|
||||||
self.assertEqual(cleaned_pt, GEOSGeometry('POINT(5 23)', srid=4326))
|
self.assertEqual(cleaned_pt, GEOSGeometry('POINT(5 23)', srid=4326))
|
||||||
self.assertEqual(4326, cleaned_pt.srid)
|
self.assertEqual(4326, cleaned_pt.srid)
|
||||||
|
with self.assertRaisesMessage(ValidationError, 'Invalid geometry value.'):
|
||||||
|
form.fields['pt'].clean('POINT(5)')
|
||||||
|
|
||||||
point = GEOSGeometry('SRID=4326;POINT(5 23)')
|
point = GEOSGeometry('SRID=4326;POINT(5 23)')
|
||||||
form = PointForm(data={'pt': 'POINT(5 23)'}, initial={'pt': point})
|
form = PointForm(data={'pt': 'POINT(5 23)'}, initial={'pt': point})
|
||||||
|
@ -132,8 +140,9 @@ class GeometryFieldTest(SimpleTestCase):
|
||||||
' rows="10" name="pt3"></textarea>',
|
' rows="10" name="pt3"></textarea>',
|
||||||
output
|
output
|
||||||
)
|
)
|
||||||
# Only the invalid PNT(0) should trigger an error log entry
|
# Only the invalid PNT(0) triggers an error log entry.
|
||||||
self.assertEqual(len(logger_calls), 1)
|
# Deserialization is called in form clean and in widget rendering.
|
||||||
|
self.assertEqual(len(logger_calls), 2)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
logger_calls[0],
|
logger_calls[0],
|
||||||
"Error creating geometry from value 'PNT(0)' (String input "
|
"Error creating geometry from value 'PNT(0)' (String input "
|
||||||
|
|
Loading…
Reference in New Issue