Python Django REST框架-序列化可选字段
我有一个具有可选字段的对象。我以这种方式定义了序列化程序:Python Django REST框架-序列化可选字段,python,django,serialization,django-rest-framework,Python,Django,Serialization,Django Rest Framework,我有一个具有可选字段的对象。我以这种方式定义了序列化程序: class ProductSerializer(serializers.Serializer): code = serializers.Field(source="Code") classification = serializers.CharField(source="Classification", required=False) 如果字段不存在,Irequired=False将绕过该字段。但是,文档中提到,这会影
class ProductSerializer(serializers.Serializer):
code = serializers.Field(source="Code")
classification = serializers.CharField(source="Classification", required=False)
如果字段不存在,Irequired=False
将绕过该字段。但是,文档中提到,这会影响反序列化而不是序列化
我得到以下错误:
'Product' object has no attribute 'Classification'
当我尝试访问序列化实例的.data
时,就会发生这种情况。(这不意味着是反序列化引起了这一问题吗?)
这种情况发生在没有分类的实例上。如果我从序列化程序类中省略分类
,它就可以正常工作
如何正确地执行此操作?使用可选字段序列化对象,也就是说。序列化程序特意设计为使用一组固定的字段,因此您不容易有选择地删除其中一个键
如果字段不存在,可以使用返回字段值或None
,或者根本不能使用序列化程序,只需编写一个直接返回响应的视图
REST framework 3.0更新序列化程序。可以在实例化的序列化程序上修改字段
。当需要动态序列化程序类时,我可能会建议更改自定义序列化程序中的字段。Django REST Framework 3.0+
现在支持动态字段,请参阅--此方法定义序列化程序中的所有字段,然后允许您有选择地删除不需要的字段
或者,您也可以对模型序列化程序执行类似操作,在序列化程序init中处理Meta.fields:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('code',)
def __init__(self, *args, **kwargs):
if SHOW_CLASSIFICATION: # add logic here for optional viewing
self.Meta.fields = list(self.Meta.fields)
self.Meta.fields.append('classification')
super(ProductSerializer, self).__init__(*args, **kwargs)
不过,你必须问问汤姆,这是否是“正确的方法”,因为它可能不符合长期计划
Django REST框架<3.0
试着这样做:
class ProductSerializer(serializers.Serializer):
...
classification = serializers.SerializerMethodField('get_classification')
def get_classification(self, obj):
return getattr(obj, 'classification', None)
多个序列化程序
@action(detail=True, serializer_class=YourSerialzierClass)
def teams_roles(self, request, pk=None):
user = self.get_object()
queryset = user.roles.all()
serializer = self.get_serializer(queryset, many=True, excluded_fields=['user'])
return Response(data=serializer.data)
另一种方法是使用不同的字段集创建多个序列化程序。一个序列化程序从另一个序列化程序继承并添加其他字段。然后,您可以使用get\u serializer\u class
方法在视图中选择适当的序列化程序。下面是一个实际示例,演示了如果用户对象与请求用户相同,我如何使用此方法调用不同的序列化程序来呈现不同的用户数据
def get_serializer_class(self):
""" An authenticated user looking at their own user object gets more data """
if self.get_object() == self.request.user:
return SelfUserSerializer
return UserSerializer
从表示中删除字段
我在安全上下文中使用的另一种方法是删除to_表示法
方法中的字段。定义一个类似于
def remove_fields_from_representation(self, representation, remove_fields):
""" Removes fields from representation of instance. Call from
.to_representation() to apply field-level security.
* remove_fields: a list of fields to remove
"""
for remove_field in remove_fields:
try:
representation.pop(remove_field)
except KeyError:
# Ignore missing key -- a child serializer could inherit a "to_representation" method
# from its parent serializer that applies security to a field not present on
# the child serializer.
pass
def to_representation(self, instance):
""" Apply field level security by removing fields for unauthorized users"""
representation = super(ProductSerializer, self).to_representation(instance)
if not permission_granted: # REPLACE WITH PERMISSION LOGIC
remove_fields = ('classification', )
self.remove_fields_from_representation(representation, remove_fields)
return representation
然后在序列化程序中,调用该方法,如
def remove_fields_from_representation(self, representation, remove_fields):
""" Removes fields from representation of instance. Call from
.to_representation() to apply field-level security.
* remove_fields: a list of fields to remove
"""
for remove_field in remove_fields:
try:
representation.pop(remove_field)
except KeyError:
# Ignore missing key -- a child serializer could inherit a "to_representation" method
# from its parent serializer that applies security to a field not present on
# the child serializer.
pass
def to_representation(self, instance):
""" Apply field level security by removing fields for unauthorized users"""
representation = super(ProductSerializer, self).to_representation(instance)
if not permission_granted: # REPLACE WITH PERMISSION LOGIC
remove_fields = ('classification', )
self.remove_fields_from_representation(representation, remove_fields)
return representation
这种方法简单而灵活,但代价是序列化有时不显示的字段。但这可能没关系。在“这是一个可怕的黑客攻击,依赖于DRF和Django的具体实现细节,但它可以工作(至少现在是这样)”文件中,我使用了一种方法,在序列化程序上的“创建”方法实现的响应中包含一些额外的调试数据:
def create(self, validated_data)
# Actual model instance creation happens here...
self.fields["debug_info"] = serializers.DictField(read_only=True)
my_model.debug_info = extra_data
return my_model
这是一种临时方法,允许我使用可浏览的API来显示在创建过程中从特定远程服务接收的一些原始响应数据。将来,我倾向于保留此功能,但将其隐藏在创建请求中的“report debugging info”(报告调试信息)标志后面,而不是默认返回较低级别的信息。为此,序列化程序具有部分
参数。如果序列化程序初始化时,可以传递partial=True
。如果您使用的是泛型或mixin,则可以重写get\u serializer
函数,如下所示:
def get_serializer(self, *args, **kwargs):
kwargs['partial'] = True
return super(YOUR_CLASS, self).get_serializer(*args, **kwargs)
那就行了
注意:这允许所有字段都是可选的,而不仅仅是特定字段。如果您只需要详细信息,可以覆盖该方法(即更新)并为各个字段添加存在性验证。下面描述的方法为我完成了这项工作。
非常简单,简单,对我来说很有用
使用的DRF版本=djangorestframework(3.1.0)
用于DRF 3的DynamicSerializer,它允许动态指定哪些字段将在序列化程序中使用,哪些字段将被排除,哪些字段是必需的
创建Mixin
通过向继承添加DynamicSerializerMixin初始化/调整序列化程序
使用它:)
或正在运行的API
@action(detail=True, serializer_class=YourSerialzierClass)
def teams_roles(self, request, pk=None):
user = self.get_object()
queryset = user.roles.all()
serializer = self.get_serializer(queryset, many=True, excluded_fields=['user'])
return Response(data=serializer.data)
序列化程序Charfield
方法具有属性allow\u blank
默认情况下,它设置为False。
将其设置为True
将允许您在“序列化”期间将该字段标记为可选
这是您应该编写的代码
classification = serializers.CharField(source="Classification", allow_blank=True)
注意:required
属性用于反序列化。可以将这些字段序列化为None
,还是密钥根本不存在?它们根本不存在,我正在调用一个SOAP web服务,该服务具有使用SUD的可选字段,response对象表示返回的XML,在某些情况下不包括可选字段;理想情况下,我希望它们根本不存在,但是我暂时可以接受None
。考虑到目前为止框架对我的项目是多么友好,最好为不存在的键提供一个开箱即用的选项,默认设置为None
@TomChristie嘿,Tom,现在DRF 3不存在了,您是否可以使用DRF 3更新您的答案,以获得推荐的方法?我这样问是因为有几个人在建议使用DRF 3的不同方法,我不确定最好的选择是什么(见下面Mark的答案或此处David的答案:有关使用DRF 3实现这一点的方法示例,你会怎么做
classification = serializers.CharField(source="Classification", allow_blank=True)