Issue
I receive nested JSON from an API (I can't influence the structure). I want to flatten the nested fields while deserializing an object, using a django rest framework serializer. How do I do this elegantly?
Here is my current approach, which works by using nested serializers and doing the flattening in the .create()
:
from dataclasses import dataclass
from rest_framework import serializers
input_data = {
"objectName": "Johnny",
"geoInfo": {
"latitude": 1.2,
"longitude": 3.4,
},
}
flattened_output = {
"name": "Johnny",
"lat": 1.2,
"lon": 3.4,
}
@dataclass
class Thing:
name: str
lat: float
lon: float
class TheFlattener(serializers.Serializer):
class GeoInfoSerializer(serializers.Serializer):
latitude = serializers.FloatField()
longitude = serializers.FloatField()
objectName = serializers.CharField(max_length=50, source="name")
geoInfo = GeoInfoSerializer()
def create(self, validated_data):
geo_info = validated_data.pop("geoInfo")
validated_data["lat"] = geo_info["latitude"]
validated_data["lon"] = geo_info["longitude"]
return Thing(**validated_data)
serializer = TheFlattener(data=input_data)
serializer.is_valid(raise_exception=True)
assert serializer.save() == Thing(**flattened_output)
I know that when serializing objects to JSON, you can reference nested/related objects in the source
parameter e.g.
first_name = CharField(source="user.first_name")
which is really nice, but I haven't been able to find something similar for deserialization.
Solution
Credit to this thread for providing the answer: source="*"
flattens nested fields into the validated_data
.
In this case, the solution looks like this:
class TheFlattener(serializers.Serializer):
class GeoInfoSerializer(serializers.Serializer):
latitude = serializers.FloatField(source="lat") # rename here
longitude = serializers.FloatField(source="lon")
objectName = serializers.CharField(max_length=50, source="name")
geoInfo = GeoInfoSerializer(source="*") # unpack nested fields here
def create(self, validated_data):
return Thing(**validated_data)
Answered By - binnev
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.