Python django rest框架&x2B;django多态模型序列化
我想知道是否有人有一个结合Django REST框架和Django多态性的Python解决方案 鉴于:Python django rest框架&x2B;django多态模型序列化,python,django,django-rest-framework,Python,Django,Django Rest Framework,我想知道是否有人有一个结合Django REST框架和Django多态性的Python解决方案 鉴于: class GalleryItem(PolymorphicModel): gallery_item_field = models.CharField() class Photo(GalleryItem): custom_photo_field = models.CharField() class Video(GalleryItem): custom_image_fi
class GalleryItem(PolymorphicModel):
gallery_item_field = models.CharField()
class Photo(GalleryItem):
custom_photo_field = models.CharField()
class Video(GalleryItem):
custom_image_field = models.CharField()
如果我想要django rest框架中所有GalleryItem的列表,它只会给我GalleryItem(父模型)的字段,因此:id、gallery_item_字段和多态性_ctype。那不是我想要的。如果是照片实例,我需要自定义\u photo\u字段;如果是视频,我需要自定义\u image\u字段。到目前为止,我只针对GET请求测试了此字段,此操作有效:
class PhotoSerializer(serializers.ModelSerializer):
class Meta:
model = models.Photo
class VideoSerializer(serializers.ModelSerializer):
class Meta:
model = models.Video
class GalleryItemModuleSerializer(serializers.ModelSerializer):
class Meta:
model = models.GalleryItem
def to_representation(self, obj):
"""
Because GalleryItem is Polymorphic
"""
if isinstance(obj, models.Photo):
return PhotoSerializer(obj, context=self.context).to_representation(obj)
elif isinstance(obj, models.Video):
return VideoSerializer(obj, context=self.context).to_representation(obj)
return super(GalleryItemModuleSerializer, self).to_representation(obj)
对于POST和PUT请求,您可能希望执行类似的操作,如使用to_internal_value def覆盖to_表示定义。为了完成,我将
添加到\u internal_value()
实现中,因为我在最近的项目中需要它
如何确定类型
它很方便,可以区分不同的“类”;为此,我将type属性添加到基本多态模型中:
class GalleryItem(PolymorphicModel):
gallery_item_field = models.CharField()
@property
def type(self):
return self.__class__.__name__
这允许将类型
称为“字段”和“只读字段”
type
将包含python类名
向序列化程序添加类型
您可以将类型添加到“字段”和“只读字段”中
(如果要在所有子模型中使用序列化器,则需要在所有序列化器中指定类型字段)
这是一个通用的、可重用的解决方案。它适用于通用的序列化程序
,但修改它以使用ModelSerializer
并不困难。它也不处理序列化父类(在我的例子中,我更多地将父类用作接口)
使用它:
class ParentClassSerializer(PolymorphicSerializer):
"""
Serializer for ParentClass objects
"""
def get_serializer_map(self) -> Dict[str, serializers.Serializer]:
"""
Return serializer map
"""
return {
ChildClass1.__name__: ChildClass1Serializer,
ChildClass2.__name__: ChildClass2Serializer,
}
我找不到to_native
方法的任何文档。什么时候调用?我猜POST和PUT可能会稍微困难一些(尽管仍然可行),因为您需要在验证之前确定用户打算提交什么(如果缺少字段,可能无法确定)。我的意思是,在写请求时使用单独的端点更干净。将改为\u native
改为改为\u representation
。很好的解决方案!您是否能够将其与DRF的可浏览文档集成?谢谢,我不熟悉可浏览文档,所以我不熟悉。谢谢您提供此解决方案。快速提示:序列化程序映射的类型应该是Dict[str,type[serializers.serializer]]
而不是Dict[str,serializers.serializer]
from typing import Dict, Type
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) -> Dict[str, Type[serializers.Serializer]]:
"""
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
"""
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']]
return serializer(context=self.context).create(validated_data)
class ParentClassSerializer(PolymorphicSerializer):
"""
Serializer for ParentClass objects
"""
def get_serializer_map(self) -> Dict[str, serializers.Serializer]:
"""
Return serializer map
"""
return {
ChildClass1.__name__: ChildClass1Serializer,
ChildClass2.__name__: ChildClass2Serializer,
}