Fixed #33742 -- Added id to GeoJSON serializer.

This commit is contained in:
Samir Shah 2022-05-28 12:33:15 +03:00 committed by Mariusz Felisiak
parent 9a3b7e5e2b
commit 6f73eb9d90
4 changed files with 26 additions and 1 deletions

View File

@ -13,6 +13,7 @@ class Serializer(JSONSerializer):
def _init_options(self): def _init_options(self):
super()._init_options() super()._init_options()
self.geometry_field = self.json_kwargs.pop("geometry_field", None) 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) self.srid = self.json_kwargs.pop("srid", 4326)
if ( if (
self.selected_fields is not None self.selected_fields is not None
@ -46,6 +47,7 @@ class Serializer(JSONSerializer):
def get_dump_object(self, obj): def get_dump_object(self, obj):
data = { data = {
"type": "Feature", "type": "Feature",
"id": obj.pk if self.id_field is None else getattr(obj, self.id_field),
"properties": self._current, "properties": self._current,
} }
if ( if (

View File

@ -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 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). 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 * ``srid``: The SRID to use for the ``geometry`` content. Defaults to 4326
(WGS 84). (WGS 84).
@ -52,6 +55,7 @@ Would output::
'features': [ 'features': [
{ {
'type': 'Feature', 'type': 'Feature',
'id': 1,
'geometry': { 'geometry': {
'type': 'Point', 'type': 'Point',
'coordinates': [-87.650175, 41.850385] 'coordinates': [-87.650175, 41.850385]
@ -66,3 +70,8 @@ Would output::
When the ``fields`` parameter is not specified, the ``geojson`` serializer adds When the ``fields`` parameter is not specified, the ``geojson`` serializer adds
a ``pk`` key to the ``properties`` dictionary with the primary key of the a ``pk`` key to the ``properties`` dictionary with the primary key of the
object as the value. 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.

View File

@ -53,7 +53,9 @@ Minor features
:mod:`django.contrib.gis` :mod:`django.contrib.gis`
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
* ... * The :doc:`GeoJSON serializer </ref/contrib/gis/serializers>` now outputs the
``id`` key for serialized features, which defaults to the primary key of
objects.
:mod:`django.contrib.messages` :mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -27,6 +27,7 @@ class GeoJSONSerializerTests(TestCase):
self.assertEqual(geodata["features"][0]["geometry"]["type"], "Point") self.assertEqual(geodata["features"][0]["geometry"]["type"], "Point")
self.assertEqual(geodata["features"][0]["properties"]["name"], "Chicago") self.assertEqual(geodata["features"][0]["properties"]["name"], "Chicago")
first_city = City.objects.order_by("name").first() 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)) self.assertEqual(geodata["features"][0]["properties"]["pk"], str(first_city.pk))
def test_geometry_field_option(self): def test_geometry_field_option(self):
@ -61,6 +62,17 @@ class GeoJSONSerializerTests(TestCase):
geodata = json.loads(geojson) geodata = json.loads(geojson)
self.assertEqual(geodata["features"][0]["geometry"]["type"], "Polygon") 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): def test_fields_option(self):
""" """
The fields option allows to define a subset of fields to be present in The fields option allows to define a subset of fields to be present in