clafoutis
clafoutis

Reputation: 113

Dynamic nested serializer field Django REST Framework

I am trying to have a serializer of a Parent model, with a nested serializer as a field, being different regarding another string field.

For example, if the registry_type field is equal to intra I want to use _IntraRegistrySerializer to serialize/deserialize the registry_data field, but if registry_type is equal to slack, I want to use _SlackRegistrySerializer for the same field.

I managed to have the serialization working doing this:

class RegistrySerializer(serializers.ModelSerializer):

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if isinstance(instance, IntraRegistry):
            data["registry_type"] = "intra"
            data["registry_data"] = _IntraRegistrySerializer(instance=instance).data
        if isinstance(instance, SlackRegistry):
            data["registry_type"] = "slack"
            data["registry_data"] = _SlackRegistrySerializer(instance=instance).data
        return data

    class Meta:
        # `Registry` being the parent model of both `IntraRegistry` and `SlackRegistry`
        model = Registry
        fields = ["id", "description"]

But it only does half of what I would like to do.

I tried overloading methods, using SerializerMethodField, and even though I keep on searching and reading the doc I can't manage to find a solution.

Upvotes: 1

Views: 974

Answers (1)

aredzko
aredzko

Reputation: 1730

This does seem like a good SerializerMethodField case:

class RegistrySerializer(serializers.ModelSerializer):
    registry_type = serializers.SerializerMethodField()
    registry_data = serializers.SerializerMethodField()

    def get_registry_type(self, obj):
        if isinstance(instance, IntraRegistry):
            return "intra"
        if isinstance(instance, SlackRegistry):
            return "slack"

    def get_registry_data(self, obj):
        if isinstance(instance, IntraRegistry):
            return _IntraRegistrySerializer(instance=obj, context=self.context).data
        if isinstance(instance, SlackRegistry):
            return _SlackRegistrySerializer(instance=obj, context=self.context).data

    class Meta:
        # `Registry` being the parent model of both `IntraRegistry` and `SlackRegistry`
        model = Registry
        fields = ["id", "description", "registry_type", "registry_data"]

The above is the implementation of the serializer method fields and should work since both of the registries inherit from Registry.

You may still need to tweak it to your needs. One difference compared to the current implementation is that the registry_type and registry_data will now always be present. They'll be null if this is a Registry object type or some other child type not handled here.

Upvotes: 1

Related Questions