diff --git a/django/contrib/gis/serializers/geojson.py b/django/contrib/gis/serializers/geojson.py index 865e90caec..072ee9dc48 100644 --- a/django/contrib/gis/serializers/geojson.py +++ b/django/contrib/gis/serializers/geojson.py @@ -13,6 +13,7 @@ class Serializer(JSONSerializer): def _init_options(self): super()._init_options() self.geometry_field = self.json_kwargs.pop("geometry_field", None) + self.id_field = self.json_kwargs.pop("id_field", None) self.srid = self.json_kwargs.pop("srid", 4326) if ( self.selected_fields is not None @@ -46,6 +47,7 @@ class Serializer(JSONSerializer): def get_dump_object(self, obj): data = { "type": "Feature", + "id": obj.pk if self.id_field is None else getattr(obj, self.id_field), "properties": self._current, } if ( diff --git a/docs/ref/contrib/gis/serializers.txt b/docs/ref/contrib/gis/serializers.txt index 5ab3e56704..f3d465c385 100644 --- a/docs/ref/contrib/gis/serializers.txt +++ b/docs/ref/contrib/gis/serializers.txt @@ -25,6 +25,9 @@ serializer accepts the following additional option when it is called by have a model with more than one geometry field and you don't want to use the first defined geometry field (by default, the first geometry field is picked). +* ``id_field``: A string containing the name of a field to use for the ``id`` + key of the GeoJSON feature. By default, the primary key of objects is used. + * ``srid``: The SRID to use for the ``geometry`` content. Defaults to 4326 (WGS 84). @@ -52,6 +55,7 @@ Would output:: 'features': [ { 'type': 'Feature', + 'id': 1, 'geometry': { 'type': 'Point', 'coordinates': [-87.650175, 41.850385] @@ -66,3 +70,8 @@ Would output:: When the ``fields`` parameter is not specified, the ``geojson`` serializer adds a ``pk`` key to the ``properties`` dictionary with the primary key of the object as the value. + +.. versionchanged:: 4.2 + + The ``id`` key for serialized features was added. Also, the ``id_field`` + option was added to the ``geojson`` serializer. diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt index 0d95f68654..0c80c5b103 100644 --- a/docs/releases/4.2.txt +++ b/docs/releases/4.2.txt @@ -53,7 +53,9 @@ Minor features :mod:`django.contrib.gis` ~~~~~~~~~~~~~~~~~~~~~~~~~ -* ... +* The :doc:`GeoJSON serializer ` now outputs the + ``id`` key for serialized features, which defaults to the primary key of + objects. :mod:`django.contrib.messages` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/gis_tests/geoapp/test_serializers.py b/tests/gis_tests/geoapp/test_serializers.py index 44066daee9..ecff6e6471 100644 --- a/tests/gis_tests/geoapp/test_serializers.py +++ b/tests/gis_tests/geoapp/test_serializers.py @@ -27,6 +27,7 @@ class GeoJSONSerializerTests(TestCase): self.assertEqual(geodata["features"][0]["geometry"]["type"], "Point") self.assertEqual(geodata["features"][0]["properties"]["name"], "Chicago") first_city = City.objects.order_by("name").first() + self.assertEqual(geodata["features"][0]["id"], first_city.pk) self.assertEqual(geodata["features"][0]["properties"]["pk"], str(first_city.pk)) def test_geometry_field_option(self): @@ -61,6 +62,17 @@ class GeoJSONSerializerTests(TestCase): geodata = json.loads(geojson) self.assertEqual(geodata["features"][0]["geometry"]["type"], "Polygon") + def test_id_field_option(self): + """ + By default Django uses the pk of the object as the id for a feature. + The 'id_field' option can be used to specify a different field to use + as the id. + """ + cities = City.objects.order_by("name") + geojson = serializers.serialize("geojson", cities, id_field="name") + geodata = json.loads(geojson) + self.assertEqual(geodata["features"][0]["id"], cities[0].name) + def test_fields_option(self): """ The fields option allows to define a subset of fields to be present in