Loading django/contrib/gis/apps.py +5 −0 Original line number Diff line number Diff line from django.apps import AppConfig from django.core import serializers from django.utils.translation import ugettext_lazy as _ Loading @@ -6,3 +7,7 @@ from django.utils.translation import ugettext_lazy as _ class GISConfig(AppConfig): name = 'django.contrib.gis' verbose_name = _("GIS") def ready(self): if 'geojson' not in serializers.BUILTIN_SERIALIZERS: serializers.BUILTIN_SERIALIZERS['geojson'] = "django.contrib.gis.serializers.geojson" django/contrib/gis/serializers/__init__.py 0 → 100644 +0 −0 Empty file added. django/contrib/gis/serializers/geojson.py 0 → 100644 +68 −0 Original line number Diff line number Diff line from __future__ import unicode_literals from django.contrib.gis.gdal import HAS_GDAL from django.core.serializers.base import SerializerDoesNotExist, SerializationError from django.core.serializers.json import Serializer as JSONSerializer if HAS_GDAL: from django.contrib.gis.gdal import CoordTransform, SpatialReference class Serializer(JSONSerializer): """ Convert a queryset to GeoJSON, http://geojson.org/ """ 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)) 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) def end_serialization(self): self.stream.write(']}') def start_object(self, obj): super(Serializer, self).start_object(obj) self._geometry = None if self.geometry_field is None: # Find the first declared geometry field for field in obj._meta.fields: if hasattr(field, 'geom_type'): self.geometry_field = field.name break def get_dump_object(self, obj): data = { "type": "Feature", "properties": self._current, } if self._geometry: if self._geometry.srid != self.srs.srid: # If needed, transform the geometry in the srid of the global geojson srid if self._geometry.srid not in self._cts: self._cts[self._geometry.srid] = CoordTransform(self._geometry.srs, self.srs) self._geometry.transform(self._cts[self._geometry.srid]) data["geometry"] = eval(self._geometry.geojson) else: data["geometry"] = None return data def handle_field(self, obj, field): if field.name == self.geometry_field: self._geometry = field._get_val_from_obj(obj) else: super(Serializer, self).handle_field(obj, field) class Deserializer(object): def __init__(self, *args, **kwargs): raise SerializerDoesNotExist("geojson is a serialization-only serializer") django/contrib/gis/tests/geoapp/models.py +6 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,12 @@ class Track(NamedModel): line = models.LineStringField() class MultiFields(NamedModel): city = models.ForeignKey(City) point = models.PointField() poly = models.PolygonField() class Truth(models.Model): val = models.BooleanField(default=False) Loading django/contrib/gis/tests/geoapp/test_serializers.py 0 → 100644 +81 −0 Original line number Diff line number Diff line from __future__ import unicode_literals import json from django.contrib.gis.geos import HAS_GEOS from django.core import serializers from django.test import TestCase, skipUnlessDBFeature from .models import City, MultiFields, PennsylvaniaCity if HAS_GEOS: from django.contrib.gis.geos import LinearRing, Point, Polygon @skipUnlessDBFeature("gis_enabled") class GeoJSONSerializerTests(TestCase): fixtures = ['initial'] def test_builtin_serializers(self): """ 'geojson' should be listed in available serializers. """ all_formats = set(serializers.get_serializer_formats()) public_formats = set(serializers.get_public_serializer_formats()) self.assertIn('geojson', all_formats), self.assertIn('geojson', public_formats) def test_serialization_base(self): geojson = serializers.serialize('geojson', City.objects.all().order_by('name')) try: geodata = json.loads(geojson) except Exception: self.fail("Serialized output is not valid JSON") self.assertEqual(len(geodata['features']), len(City.objects.all())) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Point') self.assertEqual(geodata['features'][0]['properties']['name'], 'Chicago') def test_geometry_field_option(self): """ When a model has several geometry fields, the 'geometry_field' option can be used to specify the field to use as the 'geometry' key. """ MultiFields.objects.create( city=City.objects.first(), name='Name', point=Point(5, 23), poly=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))) geojson = serializers.serialize('geojson', MultiFields.objects.all()) geodata = json.loads(geojson) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Point') geojson = serializers.serialize('geojson', MultiFields.objects.all(), geometry_field='poly') geodata = json.loads(geojson) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Polygon') def test_fields_option(self): """ The fields option allows to define a subset of fields to be present in the 'properties' of the generated output. """ PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)') geojson = serializers.serialize('geojson', PennsylvaniaCity.objects.all(), fields=('county', 'point')) geodata = json.loads(geojson) self.assertIn('county', geodata['features'][0]['properties']) self.assertNotIn('founded', geodata['features'][0]['properties']) def test_srid_option(self): geojson = serializers.serialize('geojson', City.objects.all().order_by('name'), srid=2847) geodata = json.loads(geojson) self.assertEqual( [int(c) for c in geodata['features'][0]['geometry']['coordinates']], [1564802, 5613214]) def test_deserialization_exception(self): """ GeoJSON cannot be deserialized. """ with self.assertRaises(serializers.base.SerializerDoesNotExist): serializers.deserialize('geojson', '{}') Loading
django/contrib/gis/apps.py +5 −0 Original line number Diff line number Diff line from django.apps import AppConfig from django.core import serializers from django.utils.translation import ugettext_lazy as _ Loading @@ -6,3 +7,7 @@ from django.utils.translation import ugettext_lazy as _ class GISConfig(AppConfig): name = 'django.contrib.gis' verbose_name = _("GIS") def ready(self): if 'geojson' not in serializers.BUILTIN_SERIALIZERS: serializers.BUILTIN_SERIALIZERS['geojson'] = "django.contrib.gis.serializers.geojson"
django/contrib/gis/serializers/geojson.py 0 → 100644 +68 −0 Original line number Diff line number Diff line from __future__ import unicode_literals from django.contrib.gis.gdal import HAS_GDAL from django.core.serializers.base import SerializerDoesNotExist, SerializationError from django.core.serializers.json import Serializer as JSONSerializer if HAS_GDAL: from django.contrib.gis.gdal import CoordTransform, SpatialReference class Serializer(JSONSerializer): """ Convert a queryset to GeoJSON, http://geojson.org/ """ 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)) 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) def end_serialization(self): self.stream.write(']}') def start_object(self, obj): super(Serializer, self).start_object(obj) self._geometry = None if self.geometry_field is None: # Find the first declared geometry field for field in obj._meta.fields: if hasattr(field, 'geom_type'): self.geometry_field = field.name break def get_dump_object(self, obj): data = { "type": "Feature", "properties": self._current, } if self._geometry: if self._geometry.srid != self.srs.srid: # If needed, transform the geometry in the srid of the global geojson srid if self._geometry.srid not in self._cts: self._cts[self._geometry.srid] = CoordTransform(self._geometry.srs, self.srs) self._geometry.transform(self._cts[self._geometry.srid]) data["geometry"] = eval(self._geometry.geojson) else: data["geometry"] = None return data def handle_field(self, obj, field): if field.name == self.geometry_field: self._geometry = field._get_val_from_obj(obj) else: super(Serializer, self).handle_field(obj, field) class Deserializer(object): def __init__(self, *args, **kwargs): raise SerializerDoesNotExist("geojson is a serialization-only serializer")
django/contrib/gis/tests/geoapp/models.py +6 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,12 @@ class Track(NamedModel): line = models.LineStringField() class MultiFields(NamedModel): city = models.ForeignKey(City) point = models.PointField() poly = models.PolygonField() class Truth(models.Model): val = models.BooleanField(default=False) Loading
django/contrib/gis/tests/geoapp/test_serializers.py 0 → 100644 +81 −0 Original line number Diff line number Diff line from __future__ import unicode_literals import json from django.contrib.gis.geos import HAS_GEOS from django.core import serializers from django.test import TestCase, skipUnlessDBFeature from .models import City, MultiFields, PennsylvaniaCity if HAS_GEOS: from django.contrib.gis.geos import LinearRing, Point, Polygon @skipUnlessDBFeature("gis_enabled") class GeoJSONSerializerTests(TestCase): fixtures = ['initial'] def test_builtin_serializers(self): """ 'geojson' should be listed in available serializers. """ all_formats = set(serializers.get_serializer_formats()) public_formats = set(serializers.get_public_serializer_formats()) self.assertIn('geojson', all_formats), self.assertIn('geojson', public_formats) def test_serialization_base(self): geojson = serializers.serialize('geojson', City.objects.all().order_by('name')) try: geodata = json.loads(geojson) except Exception: self.fail("Serialized output is not valid JSON") self.assertEqual(len(geodata['features']), len(City.objects.all())) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Point') self.assertEqual(geodata['features'][0]['properties']['name'], 'Chicago') def test_geometry_field_option(self): """ When a model has several geometry fields, the 'geometry_field' option can be used to specify the field to use as the 'geometry' key. """ MultiFields.objects.create( city=City.objects.first(), name='Name', point=Point(5, 23), poly=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))) geojson = serializers.serialize('geojson', MultiFields.objects.all()) geodata = json.loads(geojson) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Point') geojson = serializers.serialize('geojson', MultiFields.objects.all(), geometry_field='poly') geodata = json.loads(geojson) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Polygon') def test_fields_option(self): """ The fields option allows to define a subset of fields to be present in the 'properties' of the generated output. """ PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)') geojson = serializers.serialize('geojson', PennsylvaniaCity.objects.all(), fields=('county', 'point')) geodata = json.loads(geojson) self.assertIn('county', geodata['features'][0]['properties']) self.assertNotIn('founded', geodata['features'][0]['properties']) def test_srid_option(self): geojson = serializers.serialize('geojson', City.objects.all().order_by('name'), srid=2847) geodata = json.loads(geojson) self.assertEqual( [int(c) for c in geodata['features'][0]['geometry']['coordinates']], [1564802, 5613214]) def test_deserialization_exception(self): """ GeoJSON cannot be deserialized. """ with self.assertRaises(serializers.base.SerializerDoesNotExist): serializers.deserialize('geojson', '{}')