DRF如何序列化模型继承? (读/写)

时间:2018-02-21 16:54:18

标签: python django django-models django-rest-framework

我有一些模特

class RootModel(models.Model):
    # Some fields

class ElementModel(models.Model):
    root = models.ForeignKey(RootModel, related_name='elements', on_delete=models.CASCADE)

class TextModel(ElementModel):
    text = models.TextField()

class BooleanModel(ElementModel):
    value = models.BooleanField()

视图集

class RootViewSet(viewsets.ModelViewSet):
    queryset = RootModel.objects.all()
    serializer_class = RootSerializer

和序列化程序

class TextSerializer(serializers.ModelSerializer):
    type = serializers.SerializerMethodField()

    class Meta:
        model = TextModel
        fields = '__all__'

    def get_type(self, obj):
        return 'TEXT'


class BooleanSerializer(serializers.ModelSerializer):
    type = serializers.SerializerMethodField()

    class Meta:
        model = BooleanModel
        fields = '__all__'

    def get_type(self, obj):
        return 'BOOL'


class RootSerializer(WritableNestedModelSerializer):
    elements = ...
    class Meta:
        model = RootModel
        fields = '__all__'

WritableNestedModelSerializer来自drf_writable_nested扩展名。

我想获取/ POST / PUT包含所有数据的根

使用GET的示例(POST / PUT的数据相同)

{
    elements: [
        {
            type: "TEXT",
            text: "my awesome text"
        },
        {
            type: "BOOL",
            value: true
        }
    ],
    ...
    root fields
    ...
}

RootSerializer中元素字段的最佳方法是什么?

我也希望获得OPTIONS方法的信息,我该怎么办呢?

由于

1 个答案:

答案 0 :(得分:0)

最后我找到了解决方案。

首先我们需要一个PolymorphicSerializer类:

from enum import Enum

from rest_framework import serializers


class PolymorphicSerializer(serializers.Serializer):
    """
    Serializer to handle multiple subclasses of another class

    - For serialized dict representations, a 'type' key with the class name as
      the value is expected: ex. {'type': 'Decimal', ... }
    - This type information is used in tandem with get_serializer_map(...) to
      manage serializers for multiple subclasses
    """

    def get_serializer_map(self):
        """
        Return a dict to map class names to their respective serializer classes

        To be implemented by all PolymorphicSerializer subclasses
        """
        raise NotImplementedError

    def to_representation(self, obj):
        """
        Translate object to internal data representation

        Override to allow polymorphism
        """
        if hasattr(obj, 'get_type'):
            type_str = obj.get_type()
            if isinstance(type_str, Enum):
                type_str = type_str.value
        else:
            type_str = obj.__class__.__name__

        try:
            serializer = self.get_serializer_map()[type_str]
        except KeyError:
            raise ValueError('Serializer for "{}" does not exist'.format(type_str), )

        data = serializer(obj, context=self.context).to_representation(obj)
        data['type'] = type_str
        return data

    def to_internal_value(self, data):
        """
        Validate data and initialize primitive types

        Override to allow polymorphism
        """
        try:
            type_str = data['type']
        except KeyError:
            raise serializers.ValidationError({
                'type': 'This field is required',
            })

        try:
            serializer = self.get_serializer_map()[type_str]
        except KeyError:
            raise serializers.ValidationError({
                'type': 'Serializer for "{}" does not exist'.format(type_str),
            })

        validated_data = serializer(context=self.context).to_internal_value(data)
        validated_data['type'] = type_str
        return validated_data

    def create(self, validated_data):
        """
        Translate validated data representation to object

        Override to allow polymorphism
        """
        serializer = self.get_serializer_map()[validated_data['type']]
        validated_data.pop('type')
        return serializer(context=self.context).create(validated_data)

    def update(self, instance, validated_data):
        serializer = self.get_serializer_map()[validated_data['type']]
        validated_data.pop('type')
        return serializer(context=self.context).update(instance, validated_data)

现在:

class ElementSerializer(PolymorphicSerializer):

    class Meta:
        model = ElementModel

    def get_serializer_map(self):
        return {
            BooleanSerializer.__class__: BooleanSerializer,
            TextSerializer.__class__: TextSerializer,
        }

class RootSerializer(WritableNestedModelSerializer):
    elements = ElementSerializer(many=True)
    class Meta:
        model = RootModel
        fields = '__all__'

参考链接:https://stackoverflow.com/a/44727343/5367584