如何从序列化程序输出中动态删除字段
How to dynamically remove fields from serializer output
我正在使用 Django Rest 框架开发 API,我想从序列化程序中动态删除字段。问题是我需要根据另一个字段的值删除它们。我怎么能那样做?
我有一个像这样的序列化器:
class DynamicSerliazer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
url = serializers.SerializerMethodField()
title = serializers.SerializerMethodField()
elements = serializers.SerializerMethodField()
def __init__(self, *args, **kwargs):
super(DynamicSerliazer, self).__init__(*args, **kwargs)
if self.fields and is_mobile_platform(self.context.get('request', None)) and "url" in self.fields:
self.fields.pop("url")
如您所见,我已经删除了 "url" 字段,具体取决于请求是否是从移动平台完成的。但是,我想根据 "type" 值删除 "elements" 字段。我应该怎么做?
提前致谢
您可以customize the serialization behavior通过覆盖序列化器中的to_representation()
方法。
class DynamicSerliazer(serializers.ModelSerializer):
def to_representation(self, obj):
# get the original representation
ret = super(DynamicSerializer, self).to_representation(obj)
# remove 'url' field if mobile request
if is_mobile_platform(self.context.get('request', None)):
ret.pop('url')
# here write the logic to check whether `elements` field is to be removed
# pop 'elements' from 'ret' if condition is True
# return the modified representation
return ret
您可以创建多个序列化器并在视图中选择合适的一个
class IndexView(APIView):
def get_serializer_class(self):
if self.request.GET['flag']:
return SerializerA
return SerializerB
使用继承让序列化器变干。
我的问题和你的有点相似,我用继承解决了。
class StaticSerializer(serializers.ModelSerializer):
class Meta:
model = StaticModel
fields = (
'first_name', 'last_name', 'password', 'username',
'email'
)
class DynamicSerializer(StaticSerializer):
class Meta:
model = StaticModel
fields = (
'first_name',
)
解决方案(ViewSet 混合)
我已经通过编写自己的 ViewSet mixin 解决了这个问题。它提供了非常简单和 DRY 的方法来根据请求操作覆盖序列化程序。
class ActionBasedSerializerClassMixin(viewsets.ModelViewSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def get_serializer_class(self):
attr_name = f'{self.action}_serializer_class'
if hasattr(self, attr_name):
serializer_class = getattr(self, attr_name)
self.serializer_class = serializer_class
return super().get_serializer_class()
用法
要在您的视图集中使用此 mixin 继承自它(它必须在 ModelViewSet 父级之前)。
默认序列化程序始终用作回退
要在列表操作上使用不同的序列化程序,只需在您的视图集中设置属性 list_serializer_class:
class MyViewSet(ViewSet):
serializer_class = MySerializer
list_serializer_class = MyListSerializer
使用此代码,当操作为 'list' 时,您将拥有 MyListSerializer,而对于所有其他操作,您将拥有 MySerializer。
相同的模式适用于所有其他操作类型:列出、创建、检索、更新、partial_update、销毁。
您只需附加 _serializer_class 即可获得所需的属性名称。
序列化程序应该是什么样子
class MySerializer(serializers.ModelSerializer):
some_reverse_rel = MyOtherSerializer(many=True, read_only=True)
class Meta:
model = MyModel
fields = ['field1', 'field2', 'foo', 'bar', 'some_reverse_rel']
class MyListSerailizer(MySerializer): # Note that we inherit from previous serializer
some_reverse_rel = None # Getting rid of reverse relationship
class Meta(MySerializer.Meta):
fields = ['foo', 'bar', 'field1']
我正在使用 Django Rest 框架开发 API,我想从序列化程序中动态删除字段。问题是我需要根据另一个字段的值删除它们。我怎么能那样做? 我有一个像这样的序列化器:
class DynamicSerliazer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
url = serializers.SerializerMethodField()
title = serializers.SerializerMethodField()
elements = serializers.SerializerMethodField()
def __init__(self, *args, **kwargs):
super(DynamicSerliazer, self).__init__(*args, **kwargs)
if self.fields and is_mobile_platform(self.context.get('request', None)) and "url" in self.fields:
self.fields.pop("url")
如您所见,我已经删除了 "url" 字段,具体取决于请求是否是从移动平台完成的。但是,我想根据 "type" 值删除 "elements" 字段。我应该怎么做?
提前致谢
您可以customize the serialization behavior通过覆盖序列化器中的to_representation()
方法。
class DynamicSerliazer(serializers.ModelSerializer):
def to_representation(self, obj):
# get the original representation
ret = super(DynamicSerializer, self).to_representation(obj)
# remove 'url' field if mobile request
if is_mobile_platform(self.context.get('request', None)):
ret.pop('url')
# here write the logic to check whether `elements` field is to be removed
# pop 'elements' from 'ret' if condition is True
# return the modified representation
return ret
您可以创建多个序列化器并在视图中选择合适的一个
class IndexView(APIView):
def get_serializer_class(self):
if self.request.GET['flag']:
return SerializerA
return SerializerB
使用继承让序列化器变干。
我的问题和你的有点相似,我用继承解决了。
class StaticSerializer(serializers.ModelSerializer):
class Meta:
model = StaticModel
fields = (
'first_name', 'last_name', 'password', 'username',
'email'
)
class DynamicSerializer(StaticSerializer):
class Meta:
model = StaticModel
fields = (
'first_name',
)
解决方案(ViewSet 混合)
我已经通过编写自己的 ViewSet mixin 解决了这个问题。它提供了非常简单和 DRY 的方法来根据请求操作覆盖序列化程序。
class ActionBasedSerializerClassMixin(viewsets.ModelViewSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def get_serializer_class(self):
attr_name = f'{self.action}_serializer_class'
if hasattr(self, attr_name):
serializer_class = getattr(self, attr_name)
self.serializer_class = serializer_class
return super().get_serializer_class()
用法
要在您的视图集中使用此 mixin 继承自它(它必须在 ModelViewSet 父级之前)。 默认序列化程序始终用作回退 要在列表操作上使用不同的序列化程序,只需在您的视图集中设置属性 list_serializer_class:
class MyViewSet(ViewSet):
serializer_class = MySerializer
list_serializer_class = MyListSerializer
使用此代码,当操作为 'list' 时,您将拥有 MyListSerializer,而对于所有其他操作,您将拥有 MySerializer。 相同的模式适用于所有其他操作类型:列出、创建、检索、更新、partial_update、销毁。 您只需附加 _serializer_class 即可获得所需的属性名称。
序列化程序应该是什么样子
class MySerializer(serializers.ModelSerializer):
some_reverse_rel = MyOtherSerializer(many=True, read_only=True)
class Meta:
model = MyModel
fields = ['field1', 'field2', 'foo', 'bar', 'some_reverse_rel']
class MyListSerailizer(MySerializer): # Note that we inherit from previous serializer
some_reverse_rel = None # Getting rid of reverse relationship
class Meta(MySerializer.Meta):
fields = ['foo', 'bar', 'field1']