Commit 41eb70f7 authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #15271 -- Defined a to_python method for GeometryField

Thanks volrath and copelco for their work on the patch.
parent 45a1a54b
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _

# While this couples the geographic forms to the GEOS library,
# it decouples from database (by not importing SpatialBackend).
from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.geos import GEOSException, GEOSGeometry

class GeometryField(forms.Field):
    """
@@ -31,6 +31,15 @@ class GeometryField(forms.Field):
        self.null = kwargs.pop('null', True)
        super(GeometryField, self).__init__(**kwargs)

    def to_python(self, value):
        """
        Transforms the value to a Geometry object.
        """
        try:
            return GEOSGeometry(value)
        except (GEOSException, ValueError, TypeError):
            raise forms.ValidationError(self.error_messages['invalid_geom'])

    def clean(self, value):
        """
        Validates that the input value can be converted to a Geometry
@@ -44,11 +53,8 @@ class GeometryField(forms.Field):
            else:
                raise forms.ValidationError(self.error_messages['no_geom'])

        # Trying to create a Geometry object from the form value.
        try:
            geom = GEOSGeometry(value)
        except:
            raise forms.ValidationError(self.error_messages['invalid_geom'])
        # Transform the value to a python object first
        geom = self.to_python(value)

        # Ensuring that the geometry is of the correct type (indicated
        # using the OGC string label).
+17 −0
Original line number Diff line number Diff line
@@ -56,8 +56,25 @@ class GeometryFieldTest(unittest.TestCase):

        pnt_fld = forms.GeometryField(geom_type='POINT')
        self.assertEqual(GEOSGeometry('POINT(5 23)'), pnt_fld.clean('POINT(5 23)'))
        # a WKT for any other geom_type will be properly transformed by `to_python`
        self.assertEqual(GEOSGeometry('LINESTRING(0 0, 1 1)'), pnt_fld.to_python('LINESTRING(0 0, 1 1)'))
        # but rejected by `clean`
        self.assertRaises(forms.ValidationError, pnt_fld.clean, 'LINESTRING(0 0, 1 1)')

    def test04_to_python(self):
        """
        Testing to_python returns a correct GEOSGeometry object or
        a ValidationError
        """
        fld = forms.GeometryField()
        # to_python returns the same GEOSGeometry for a WKT
        for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'):
            self.assertEqual(GEOSGeometry(wkt), fld.to_python(wkt))
        # but raises a ValidationError for any other string
        for wkt in ('POINT(5)', 'MULTI   POLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'BLAH(0 0, 1 1)'):
            self.assertRaises(forms.ValidationError, fld.to_python, wkt)


def suite():
    s = unittest.TestSuite()
    s.addTest(unittest.makeSuite(GeometryFieldTest))