我正在尝试通过覆盖 __init__ 方法将字段动态添加到 Django Rest Framework 的序列化程序。该方法类似于此处描述的方法:http://masnun.com/2015/10/21/django-rest-framework-dynamic-fields-in-serializers.html
我这样做的原因是,因为我想将字段类型动态更改为一个类型,由要序列化的实例的属性 type_ 确定。如果我一次序列化一个实例,这非常有效:
from rest_framework import serializers
from rest_framework.fields import empty
class VariableDetails:
def __init__(self, name, type_, value):
self.name = name
self.type_ = type_
self.value = value
class VariableDetailSerializer(serializers.Serializer):
TYPE_FIELD_MAP = {
'string': serializers.CharField,
'integer': serializers.IntegerField,
'float': serializers.FloatField,
}
name = serializers.CharField()
type_ = serializers.CharField()
def __init__(self, instance=None, data=empty, **kwargs):
# this is where the magic happens
super().__init__(instance, data, **kwargs)
if instance is not None:
field_type = self.TYPE_FIELD_MAP[instance.type_]
self.fields['value'] = field_type()
string_details = VariableDetails('character value', 'string', 'hello world')
integer_details = VariableDetails('integer value', 'integer', 123)
print(VariableDetailSerializer(string_details).data)
# {'name': 'character value', 'type_': 'string', 'value': 'hello world'}
print(VariableDetailSerializer(integer_details).data)
# {'name': 'integer value', 'type_': 'integer', 'value': 123}
如果我想序列化与父实例相关的 VariableDetails 的多个实例(例如将其称为 Parent),则缺少值字段:
class Parent:
def __init__(self, variable_details):
self.variable_details = variable_details
class ParentSerializer(serializers.Serializer):
variable_details = VariableDetailSerializer(many=True)
parent = Parent(variable_details=[string_details, integer_details])
print(ParentSerializer(parent).data)
# {
# 'variable_details': [
# {
# 'name': 'character_value',
# 'type_': 'string'
# # value is missing
# },
# {
# 'name': 'integer_value',
# 'type_': 'integer'
# },
# ]
# }
显然 VariableDetailSerializer.__init__ 仅在创建 ParentSerializer 期间调用一次,并且在初始化 ParentSerializer 的新实例时调用一次。在这两种情况下,instance 都是 None。因此,不会为每个 VariableDetails 调用它。
有人知道如何将字段动态添加到同时序列化列表实例的 Serializer 吗?
为了方便运行代码,我创建了一个要点:https://gist.github.com/larsrinn/861f8d50bf5bb0626d73321b546d8cb3 如果安装了 Django Rest Framework,代码应该可以复制并粘贴到 python repl 中。但是,您不需要创建 Django 项目
请您参考如下方法:
因为 VariableDetailSerializer 嵌套在 ParentSerializer 中,它的行为就像一个字段本身。在这种情况下,您可以覆盖 to_representation() 方法来执行动态类型切换。
def to_representation(self, instance):
field_type = self.TYPE_FIELD_MAP[instance.type_]
self.fields['value'] = field_type()
try:
del self._readable_fields # Clear the cache
except AttributeError:
pass
return super().to_representation(instance)
这里的主要问题是序列化程序缓存了字段,因为它不希望它们在实例之间发生变化。因此,有必要使用 del self._readable_fields 清除缓存。
当我将以上内容添加到 VariableDetailSerializer 并运行您的示例时,我得到:
{
'variable_details': [
OrderedDict([('name', u'character value'),
('type_', u'string'),
('value', u'hello world')]),
OrderedDict([('name', u'integer value'),
('type_', u'integer'),
('value', 123)])
]
}
