【问题标题】:DRF How to serialize models inheritance ? (read/write)DRF 如何序列化模型继承? (读/写)
【发布时间】:2018-08-01 08:31:07
【问题描述】:

我有一些模型

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 扩展。

我想 GET/POST/PUT 一个包含所有数据的根目录

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

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

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

我也想用 OPTIONS 方法获取信息,请问如何获取?

谢谢

【问题讨论】:

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


    【解决方案1】:

    终于找到了解决办法。

    首先我们需要一个 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-25
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 1970-01-01
      • 2019-11-17
      相关资源
      最近更新 更多