From fef195be160c57139edcade836a180076fe9d97e Mon Sep 17 00:00:00 2001 From: nippo Date: Thu, 4 Sep 2014 09:53:09 +0200 Subject: [PATCH 1/4] Adds RawQuerySet to serializer --- djgeojson/serializers.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/djgeojson/serializers.py b/djgeojson/serializers.py index a0076a1..29b145f 100644 --- a/djgeojson/serializers.py +++ b/djgeojson/serializers.py @@ -16,6 +16,7 @@ from django.db.models.base import Model from django.db.models.query import QuerySet, ValuesQuerySet +from django.db.models.query import RawQuerySet from django.forms.models import model_to_dict from django.core.serializers.python import (_get_model, Serializer as PythonSerializer, @@ -122,7 +123,7 @@ def end_object(self, obj): self.handle_field(obj, field) # Add extra-info for deserializing - if hasattr(obj, '_meta'): + if hasattr(obj, '_meta') and self.deserializing_extra: self._current['properties']['model'] = smart_text(obj._meta) # If geometry not in model fields, may be a dynamic attribute @@ -148,6 +149,7 @@ def end_serialization(self): self.options.pop('simplify', None) self.options.pop('bbox', None) self.options.pop('bbox_auto', None) + self.options.pop('deserializing_extra', None) # Optional float precision control precision = self.options.pop('precision', None) @@ -354,6 +356,7 @@ def serialize(self, queryset, **options): self.bbox_auto = options.get("bbox_auto", None) self.srid = options.get("srid", GEOJSON_DEFAULT_SRID) self.crs = options.get("crs", True) + self.deserializing_extra = options.get("deserializing_extra", True) self.start_serialization() @@ -366,6 +369,12 @@ def serialize(self, queryset, **options): elif isinstance(queryset, QuerySet): self.serialize_queryset(queryset) + # a geometry field, "geom" could be retrieve with AsText(geom) + # for example + elif isinstance(queryset, RawQuerySet) and \ + self.properties is not None : + self.serialize_queryset(queryset) + self.end_serialization() return self.getvalue() From d840ce3660994434cf0728a8114bc8bc0a4401d5 Mon Sep 17 00:00:00 2001 From: nippo Date: Thu, 4 Sep 2014 09:53:09 +0200 Subject: [PATCH 2/4] Adds RawQuerySet to serializer --- djgeojson/serializers.py | 11 ++++++++++- djgeojson/tests.py | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/djgeojson/serializers.py b/djgeojson/serializers.py index a0076a1..29b145f 100644 --- a/djgeojson/serializers.py +++ b/djgeojson/serializers.py @@ -16,6 +16,7 @@ from django.db.models.base import Model from django.db.models.query import QuerySet, ValuesQuerySet +from django.db.models.query import RawQuerySet from django.forms.models import model_to_dict from django.core.serializers.python import (_get_model, Serializer as PythonSerializer, @@ -122,7 +123,7 @@ def end_object(self, obj): self.handle_field(obj, field) # Add extra-info for deserializing - if hasattr(obj, '_meta'): + if hasattr(obj, '_meta') and self.deserializing_extra: self._current['properties']['model'] = smart_text(obj._meta) # If geometry not in model fields, may be a dynamic attribute @@ -148,6 +149,7 @@ def end_serialization(self): self.options.pop('simplify', None) self.options.pop('bbox', None) self.options.pop('bbox_auto', None) + self.options.pop('deserializing_extra', None) # Optional float precision control precision = self.options.pop('precision', None) @@ -354,6 +356,7 @@ def serialize(self, queryset, **options): self.bbox_auto = options.get("bbox_auto", None) self.srid = options.get("srid", GEOJSON_DEFAULT_SRID) self.crs = options.get("crs", True) + self.deserializing_extra = options.get("deserializing_extra", True) self.start_serialization() @@ -366,6 +369,12 @@ def serialize(self, queryset, **options): elif isinstance(queryset, QuerySet): self.serialize_queryset(queryset) + # a geometry field, "geom" could be retrieve with AsText(geom) + # for example + elif isinstance(queryset, RawQuerySet) and \ + self.properties is not None : + self.serialize_queryset(queryset) + self.end_serialization() return self.getvalue() diff --git a/djgeojson/tests.py b/djgeojson/tests.py index 312b695..b19b7ae 100644 --- a/djgeojson/tests.py +++ b/djgeojson/tests.py @@ -146,6 +146,23 @@ def test_basic(self): self.assertEqual(actual_geojson_with_prop, {"crs": {"type": "link", "properties": {"href": "http://spatialreference.org/ref/epsg/4326/", "type": "proj4"}}, "type": "FeatureCollection", "features": [{"geometry": {"type": "LineString", "coordinates": [[0.0, 0.0], [1.0, 1.0]]}, "type": "Feature", "properties": {"picture": "image.png", "model": "djgeojson.route", "upper_name": "GREEN", "name": "green"}, "id": route1.pk}, {"geometry": {"type": "LineString", "coordinates": [[0.0, 0.0], [1.0, 1.0]]}, "type": "Feature", "properties": {"picture": "image.png", "model": "djgeojson.route", "upper_name": "BLUE", "name": "blue"}, "id": route2.pk}, {"geometry": {"type": "LineString", "coordinates": [[0.0, 0.0], [1.0, 1.0]]}, "type": "Feature", "properties": {"picture": "image.png", "model": "djgeojson.route", "upper_name": "RED", "name": "red"}, "id": route3.pk}]}) + def test_basic_raw_query_set(self): + # Stuff to serialize + route1 = Route.objects.create( + name='green', geom="LINESTRING (0 0, 1 1)") + route2 = Route.objects.create( + name='blue', geom="LINESTRING (0 0, 1 1)") + route3 = Route.objects.create(name='red', geom="LINESTRING (0 0, 1 1)") + + actual_geojson = json.loads(serializers.serialize( + 'geojson', + Route.objects.raw('select id, name, AsText(geom) from djgeojson_route'), + deserializing_extra=False, + properties=['name'])) + self.assertEqual( + actual_geojson, + {"crs": {"type": "link", "properties": {"href": "http://spatialreference.org/ref/epsg/4326/", "type": "proj4"}}, "type": "FeatureCollection", "features": [{"geometry": {"type": "LineString", "coordinates": [[0.0, 0.0], [1.0, 1.0]]}, "type": "Feature", "properties": {"name": "green"}, "id": route1.pk}, {"geometry": {"type": "LineString", "coordinates": [[0.0, 0.0], [1.0, 1.0]]}, "type": "Feature", "properties": {"name": "blue"}, "id": route2.pk}, {"geometry": {"type": "LineString", "coordinates": [[0.0, 0.0], [1.0, 1.0]]}, "type": "Feature", "properties": {"name": "red"}, "id": route3.pk}]}) + def test_precision(self): serializer = Serializer() features = json.loads(serializer.serialize( From 7c9f43e8d396cefab788597d7b6cff2e254d1d89 Mon Sep 17 00:00:00 2001 From: nippo Date: Mon, 2 Feb 2015 10:24:47 +0100 Subject: [PATCH 3/4] Fixes merge --- djgeojson/serializers.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/djgeojson/serializers.py b/djgeojson/serializers.py index 6a556db..f067d9b 100644 --- a/djgeojson/serializers.py +++ b/djgeojson/serializers.py @@ -150,11 +150,7 @@ def end_serialization(self): self.options.pop('simplify', None) self.options.pop('bbox', None) self.options.pop('bbox_auto', None) -<<<<<<< HEAD self.options.pop('with_modelname', None) -======= - self.options.pop('deserializing_extra', None) ->>>>>>> 012d985bb15c3439f61f2fddf67bbd17086462f3 # Optional float precision control precision = self.options.pop('precision', None) From 6e264fd26b5a1b8bdc0dc8db543126ac378a8318 Mon Sep 17 00:00:00 2001 From: nippo Date: Sun, 15 Feb 2015 14:38:08 +0100 Subject: [PATCH 4/4] Adds more attributes to test Backbone --- djgeojson/serializers.py | 62 ++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/djgeojson/serializers.py b/djgeojson/serializers.py index f067d9b..f4d0e4e 100644 --- a/djgeojson/serializers.py +++ b/djgeojson/serializers.py @@ -3,7 +3,7 @@ This code mainly comes from @glenrobertson's django-geoson-tiles at: https://github.com/glenrobertson/django-geojson-tiles/ - Itself, adapted from @jeffkistler's geojson serializer at: https://gist.github.com/967274 + Itself, adapted from @jeffkistler's geojson serializer at: https://gist.github.com/967274 # NOQA """ try: from cStringIO import StringIO @@ -22,7 +22,8 @@ Serializer as PythonSerializer, Deserializer as PythonDeserializer) from django.core.serializers.json import DjangoJSONEncoder -from django.core.serializers.base import SerializationError, DeserializationError +from django.core.serializers.base import SerializationError +from django.core.serializers.base import DeserializationError from django.utils.encoding import smart_text @@ -68,7 +69,12 @@ class Serializer(PythonSerializer): internal_use_only = False def start_serialization(self): - self.feature_collection = {"type": "FeatureCollection", "features": []} + self.feature_collection = { + "total": "", + "page": "", + "perPage": "", + "type": "FeatureCollection", + "features": []} if self.crs is not False: self.feature_collection["crs"] = self.get_crs() @@ -82,7 +88,7 @@ def get_crs(self): crs = {} crs["type"] = "link" properties = {} - properties["href"] = "http://spatialreference.org/ref/epsg/%s/" % (str(self.srid)) + properties["href"] = "http://spatialreference.org/ref/epsg/%s/" % (str(self.srid)) # NOQA properties["type"] = "proj4" crs["properties"] = properties return crs @@ -159,7 +165,9 @@ def end_serialization(self): # Monkey patch for float precision! json.encoder.FLOAT_REPR = lambda o: format(o, '.%sf' % precision) - json.dump(self.feature_collection, self.stream, cls=DjangoGeoJSONEncoder, **self.options) + json.dump( + self.feature_collection, + self.stream, cls=DjangoGeoJSONEncoder, **self.options) json.encoder.FLOAT_REPR = floatrepr # Restore @@ -179,7 +187,7 @@ def _handle_geom(self, value): except ValueError: # if the geometry couldn't be parsed. # we can't generate valid geojson - error_msg = 'The field ["%s", "%s"] could not be parsed as a valid geometry' % ( + error_msg = 'The field ["%s", "%s"] could not be parsed as a valid geometry' % ( # NOQA self.geometry_field, value ) raise SerializationError(error_msg) @@ -188,11 +196,14 @@ def _handle_geom(self, value): if self.options.get('force2d'): wkb_w = WKBWriter() wkb_w.outdim = 2 - geometry = GEOSGeometry(wkb_w.write(geometry), srid=geometry.srid) + geometry = GEOSGeometry( + wkb_w.write(geometry), + srid=geometry.srid) # Optional geometry simplification simplify = self.options.get('simplify') if simplify is not None: - geometry = geometry.simplify(tolerance=simplify, preserve_topology=True) + geometry = geometry.simplify( + tolerance=simplify, preserve_topology=True) # Optional geometry reprojection if geometry.srid and geometry.srid != self.srid: geometry.transform(self.srid) @@ -240,7 +251,9 @@ def handle_fk_field(self, obj, field): related = related._get_pk_val() else: # Related to remote object via other field - related = smart_text(getattr(related, field.rel.field_name), strings_only=True) + related = smart_text( + getattr(related, field.rel.field_name), + strings_only=True) self._current['properties'][field.name] = related def handle_m2m_field(self, obj, field): @@ -248,16 +261,18 @@ def handle_m2m_field(self, obj, field): if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'): m2m_value = lambda value: value.natural_key() else: - m2m_value = lambda value: smart_text(value._get_pk_val(), strings_only=True) - self._current['properties'][field.name] = [m2m_value(related) - for related in getattr(obj, field.name).iterator()] + m2m_value = lambda value: smart_text( + value._get_pk_val(), strings_only=True) + self._current['properties'][field.name] = [ + m2m_value(related) for related in getattr( + obj, field.name).iterator()] def handle_reverse_field(self, obj, field, field_name): if self.use_natural_keys and hasattr(field.model, 'natural_key'): reverse_value = lambda value: value.natural_key() else: - reverse_value = lambda value: smart_text(value._get_pk_val(), strings_only=True) - values = [reverse_value(related) for related in getattr(obj, field_name).iterator()] + reverse_value = lambda value: smart_text(value._get_pk_val(), strings_only=True) # NOQA + values = [reverse_value(related) for related in getattr(obj, field_name).iterator()] # NOQA self._current['properties'][field_name] = values def serialize_object_list(self, objects): @@ -271,7 +286,7 @@ def serialize_object_list(self, objects): objdict = model_to_dict(obj) # In case geometry is not a DB field if self.geometry_field not in objdict: - objdict[self.geometry_field] = getattr(obj, self.geometry_field) + objdict[self.geometry_field] = getattr(obj, self.geometry_field) # NOQA values.append(objdict) if self.properties: extras = [f for f in self.properties if hasattr(obj, f)] @@ -301,7 +316,7 @@ def serialize_queryset(self, queryset): local_fields = opts.local_fields many_to_many_fields = opts.many_to_many reversed_fields = [obj.field for obj in opts.get_all_related_objects()] - reversed_fields += [obj.field for obj in opts.get_all_related_many_to_many_objects()] + reversed_fields += [obj.field for obj in opts.get_all_related_many_to_many_objects()] # NOQA # populate each queryset obj as a feature for obj in queryset: @@ -316,7 +331,7 @@ def serialize_queryset(self, queryset): # as it is in the id of the feature # except if explicitly listed in properties if field.name == opts.pk.name and \ - (self.properties is None or 'id' not in self.properties): + (self.properties is None or 'id' not in self.properties): # NOQA continue # ignore other geometries if isinstance(field, GeometryField): @@ -324,21 +339,21 @@ def serialize_queryset(self, queryset): if field.serialize or field.primary_key: if field.rel is None: - if self.properties is None or field.attname in self.properties: + if self.properties is None or field.attname in self.properties: # NOQA self.handle_field(obj, field.name) else: - if self.properties is None or field.attname[:-3] in self.properties: + if self.properties is None or field.attname[:-3] in self.properties: # NOQA self.handle_fk_field(obj, field) for field in many_to_many_fields: if field.serialize: - if self.properties is None or field.attname in self.properties: + if self.properties is None or field.attname in self.properties: # NOQA self.handle_m2m_field(obj, field) for field in reversed_fields: if field.serialize: - field_name = field.rel.related_name or opts.object_name.lower() - if self.properties is None or field_name in self.properties: + field_name = field.rel.related_name or opts.object_name.lower() # NOQA + if self.properties is None or field_name in self.properties: # NOQA self.handle_reverse_field(obj, field, field_name) self.end_object(obj) @@ -369,8 +384,7 @@ def serialize(self, queryset, **options): # a geometry field, "geom" could be retrieve with AsText(geom) # for example - elif isinstance(queryset, RawQuerySet) and \ - self.properties is not None : + elif isinstance(queryset, RawQuerySet) and self.properties is not None: self.serialize_queryset(queryset) self.end_serialization()