Return list of objects as dictionary with keys as the objects id with django rest framerwork Return list of objects as dictionary with keys as the objects id with django rest framerwork django django

Return list of objects as dictionary with keys as the objects id with django rest framerwork


I think you can implement the to_representation function in your Serializer.

class MySerializer(serializers.Serializer):    id = serializers.ReadOnlyField()    field1 = serializers.ReadOnlyField()    field2 = serializers.ReadOnlyField()    def to_representation(self, data):        res = super(MySerializer, self).to_representation(data)        return {res['id']: res}        # or you can fetch the id by data directly        # return {str(data.id): res}


You can traverse each item and with a dict comprehension create your desired dictionary. For example:

>>> l = [{ "id": 1, "x": 4}, { "id": 2, "x": 3}]>>> {v["id"]: v for v in l}{1: {'x': 4, 'id': 1}, 2: {'x': 3, 'id': 2}}


EDIT: current version available in a Github project and PYPI (pip install drf-keyed-list)

Here's a general-purpose class that is bi-directional (vs. the read-only implementation above):

class KeyedListSerializer(ListSerializer):    def __init__(self, *args, **kwargs):        super().__init__(*args, **kwargs)        meta = getattr(self.child, 'Meta', None)        assert hasattr(meta, 'keyed_list_serializer_field'), \            "Must provide a field name at keyed_list_serializer_field when using KeyedListSerializer"        self._keyed_field = meta.keyed_list_serializer_field    def to_internal_value(self, data):        # syntax is py3 only        data = [{**v, **{self._keyed_field: k}} for k, v in data.items()]        return super().to_internal_value(data)    def to_representation(self, data):        response = super().to_representation(data)        return {v.pop(self._keyed_field): v for v response}

For Py2, you need to make the super calls explicit and replace the indicated dictionary constructor. You use it by assigning it to your list_serializer_class and selecting a keyed_list_serializer_field (i.e. the field used as the dict key):

class MySerializer(ModelSerializer):    class Meta:        list_serializer_class = KeyedListSerializer        keyed_list_serializer_field = 'id'

The keyed_list_serializer_field should contain unique values; the above implementation doesn't check.