diff options
| author | Claude Paroz <claude@2xlibre.net> | 2015-07-18 14:50:08 +0200 |
|---|---|---|
| committer | Claude Paroz <claude@2xlibre.net> | 2015-07-20 20:22:29 +0200 |
| commit | 1da170a203819ffda7764e53e3c268b8fc2ab452 (patch) | |
| tree | 0d859a9c1ff4e7ffdee6f3bc09e536ff93e58c0b | |
| parent | 774c16d16ed67d7cf12bc2b2752768b544bdb363 (diff) | |
Fixed #25141 -- Diminished GDAL dependence during geojson serialization
Only require GDAL if contained geometries need coordinate transformations.
Thanks drepo for the report and Tim Graham for the review.
| -rw-r--r-- | django/contrib/gis/geos/collections.py | 14 | ||||
| -rw-r--r-- | django/contrib/gis/geos/geometry.py | 8 | ||||
| -rw-r--r-- | django/contrib/gis/serializers/geojson.py | 16 | ||||
| -rw-r--r-- | docs/ref/contrib/gis/serializers.txt | 14 | ||||
| -rw-r--r-- | tests/gis_tests/geoapp/test_serializers.py | 11 |
5 files changed, 47 insertions, 16 deletions
diff --git a/django/contrib/gis/geos/collections.py b/django/contrib/gis/geos/collections.py index 32176673c1..4649a895a0 100644 --- a/django/contrib/gis/geos/collections.py +++ b/django/contrib/gis/geos/collections.py @@ -2,6 +2,7 @@ This module houses the Geometry Collection objects: GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon """ +import json from ctypes import byref, c_int, c_uint from django.contrib.gis.geos import prototypes as capi @@ -84,6 +85,19 @@ class GeometryCollection(GEOSGeometry): _assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild @property + def json(self): + if self.__class__.__name__ == 'GeometryCollection': + return json.dumps({ + 'type': self.__class__.__name__, + 'geometries': [ + {'type': geom.__class__.__name__, 'coordinates': geom.coords} + for geom in self + ], + }) + return super(GeometryCollection, self).json + geojson = json + + @property def kml(self): "Returns the KML for this Geometry Collection." return '<MultiGeometry>%s</MultiGeometry>' % ''.join(g.kml for g in self) diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py index 4cbd561e3c..61bf590ac5 100644 --- a/django/contrib/gis/geos/geometry.py +++ b/django/contrib/gis/geos/geometry.py @@ -4,6 +4,7 @@ """ from __future__ import unicode_literals +import json from ctypes import addressof, byref, c_double from django.contrib.gis import gdal @@ -411,12 +412,9 @@ class GEOSGeometry(GEOSBase, ListMixin): @property def json(self): """ - Returns GeoJSON representation of this Geometry if GDAL is installed. + Returns GeoJSON representation of this Geometry. """ - if gdal.HAS_GDAL: - return self.ogr.json - else: - raise GEOSException('GeoJSON output only supported when GDAL is installed.') + return json.dumps({'type': self.__class__.__name__, 'coordinates': self.coords}) geojson = json @property diff --git a/django/contrib/gis/serializers/geojson.py b/django/contrib/gis/serializers/geojson.py index 9c15b49676..f26147a59a 100644 --- a/django/contrib/gis/serializers/geojson.py +++ b/django/contrib/gis/serializers/geojson.py @@ -17,17 +17,14 @@ class Serializer(JSONSerializer): def _init_options(self): super(Serializer, self)._init_options() self.geometry_field = self.json_kwargs.pop('geometry_field', None) - self.srs = SpatialReference(self.json_kwargs.pop('srid', 4326)) + self.srid = self.json_kwargs.pop('srid', 4326) def start_serialization(self): - if not HAS_GDAL: - # GDAL is needed for the geometry.geojson call - raise SerializationError("The geojson serializer requires the GDAL library.") self._init_options() self._cts = {} # cache of CoordTransform's self.stream.write( '{"type": "FeatureCollection", "crs": {"type": "name", "properties": {"name": "EPSG:%d"}},' - ' "features": [' % self.srs.srid) + ' "features": [' % self.srid) def end_serialization(self): self.stream.write(']}') @@ -48,10 +45,15 @@ class Serializer(JSONSerializer): "properties": self._current, } if self._geometry: - if self._geometry.srid != self.srs.srid: + if self._geometry.srid != self.srid: # If needed, transform the geometry in the srid of the global geojson srid + if not HAS_GDAL: + raise SerializationError( + 'Unable to convert geometry to SRID %s when GDAL is not installed.' % self.srid + ) if self._geometry.srid not in self._cts: - self._cts[self._geometry.srid] = CoordTransform(self._geometry.srs, self.srs) + srs = SpatialReference(self.srid) + self._cts[self._geometry.srid] = CoordTransform(self._geometry.srs, srs) self._geometry.transform(self._cts[self._geometry.srid]) data["geometry"] = eval(self._geometry.geojson) else: diff --git a/docs/ref/contrib/gis/serializers.txt b/docs/ref/contrib/gis/serializers.txt index 54b6c5727c..59266940e3 100644 --- a/docs/ref/contrib/gis/serializers.txt +++ b/docs/ref/contrib/gis/serializers.txt @@ -7,9 +7,17 @@ GeoJSON Serializer .. module:: django.contrib.gis.serializers.geojson :synopsis: Serialization of GeoDjango models in the GeoJSON format. -GeoDjango provides a specific serializer for the `GeoJSON`__ format. The GDAL -library is required for this serializer. See :doc:`/topics/serialization` for -more information on serialization. +GeoDjango provides a specific serializer for the `GeoJSON`__ format. See +:doc:`/topics/serialization` for more information on serialization. + +The GDAL library is required if any of the serialized geometries need +coordinate transformations (that is if the geometry's spatial reference system +differs from the ``srid`` serializer option). + +.. versionchanged:: 1.9 + + The GeoJSON serializer no longer needs GDAL if all geometries are in the + same coordinate system as the ``srid`` serializer option. __ http://geojson.org/ diff --git a/tests/gis_tests/geoapp/test_serializers.py b/tests/gis_tests/geoapp/test_serializers.py index 09f837417b..1bf3ec0acf 100644 --- a/tests/gis_tests/geoapp/test_serializers.py +++ b/tests/gis_tests/geoapp/test_serializers.py @@ -4,7 +4,8 @@ import json from django.contrib.gis.geos import LinearRing, Point, Polygon from django.core import serializers -from django.test import TestCase, skipUnlessDBFeature +from django.test import TestCase, mock, skipUnlessDBFeature +from django.utils import six from .models import City, MultiFields, PennsylvaniaCity @@ -70,6 +71,14 @@ class GeoJSONSerializerTests(TestCase): [int(c) for c in geodata['features'][0]['geometry']['coordinates']], [1564802, 5613214]) + @mock.patch('django.contrib.gis.serializers.geojson.HAS_GDAL', False) + def test_without_gdal(self): + # Without coordinate transformation, the serialization should succeed: + serializers.serialize('geojson', City.objects.all()) + with six.assertRaisesRegex(self, serializers.base.SerializationError, '.*GDAL is not installed'): + # Coordinate transformations need GDAL + serializers.serialize('geojson', City.objects.all(), srid=2847) + def test_deserialization_exception(self): """ GeoJSON cannot be deserialized. |
