我已经定义了如下的序列化器。我正在使用mixin来动态更改显示字段。
class SerializerTwo(serializers.ModelSerializer):
class Meta:
model = Two
fields = ('name', 'contact_number')
class SerializerOne(DynamicFieldsModelSerializer, serializers.ModelSerializer):
another_field = SerializerTwo()
class Meta:
lookup_field = 'uuid'
model = One
fields = ('status', 'another_field',)
现在我要做的是,动态传递(动态)从SerializerTwo中使用的所有字段,就像我在为SerializerOne做的那样。
我为SerializerOne做的方式是:
# where fields=('status')
SerializerOne(queryset, fields=fields)
有没有办法,我可以使用它从SerializerTwo中添加字段到上面的Serializer初始化。
# where fields=('status', 'name') name from SerializerTwo
# the double underscore notation does not work here for fields, so another_field__name cannot be used as well
SerializerOne(queryset, fields=fields)
答案 0 :(得分:1)
在遇到同样的问题之后,我找到了一个解决方案,我希望这对某些人来说是有帮助的。我修改了DynamicFieldsModelSerializer定义为here
instanceof
之后,您可以像这样使用它:
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
nested = kwargs.pop('nested', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields.keys())
for field_name in existing - allowed:
self.fields.pop(field_name)
if nested is not None:
for serializer in nested:
try:
nested_serializer = self.fields[serializer]
except:
logger.warning("Wrong nested serializer name")
continue
allowed = set(nested[serializer])
existing = set(nested_serializer.fields.keys())
for field_name in existing - allowed:
nested_serializer.fields.pop(field_name)
您可以修改我的解决方案以使用双下划线而不是另一个带有dict的kewyord,但我想将常规字段与嵌套序列化器分开。
它也可以被改进为递归,这里我只处理一个嵌套序列化器的深度
EDIT 我修改了我的代码以使用双下划线语法:
SerializerOne(queryset, nested={"another_field": ["name"]})
然后您可以像这样使用它:
def __init__(self, *args, **kwargs):
def parse_nested_fields(fields):
field_object = {"fields": []}
for f in fields:
obj = field_object
nested_fields = f.split("__")
for v in nested_fields:
if v not in obj["fields"]:
obj["fields"].append(v)
if nested_fields.index(v) < len(nested_fields) - 1:
obj[v] = obj.get(v, {"fields": []})
obj = obj[v]
return field_object
def select_nested_fields(serializer, fields):
for k in fields:
if k == "fields":
fields_to_include(serializer, fields[k])
else:
select_nested_fields(serializer.fields[k], fields[k])
def fields_to_include(serializer, fields):
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(serializer.fields.keys())
for field_name in existing - allowed:
serializer.fields.pop(field_name)
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
fields = parse_nested_fields(fields)
# Drop any fields that are not specified in the `fields` argument.
select_nested_fields(self, fields)
答案 1 :(得分:0)
@Lotram的答案不适用于返回多个值(通过many=True
)的字段。
以下代码对@Lotram的解决方案进行了改进,该解决方案适用于返回多个值的字段:
class NestedDynamicFieldsModelSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
def parse_nested_fields(fields):
field_object = {"fields": []}
for f in fields:
obj = field_object
nested_fields = f.split("__")
for v in nested_fields:
if v not in obj["fields"]:
obj["fields"].append(v)
if nested_fields.index(v) < len(nested_fields) - 1:
obj[v] = obj.get(v, {"fields": []})
obj = obj[v]
return field_object
def select_nested_fields(serializer, fields):
for k in fields:
if k == "fields":
fields_to_include(serializer, fields[k])
else:
select_nested_fields(serializer.fields[k], fields[k])
def fields_to_include(serializer, fields):
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
if isinstance(serializer, serializers.ListSerializer):
existing = set(serializer.child.fields.keys())
for field_name in existing - allowed:
serializer.child.fields.pop(field_name)
else:
existing = set(serializer.fields.keys())
for field_name in existing - allowed:
serializer.fields.pop(field_name)
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(NestedDynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# import pdb; pdb.set_trace()
fields = parse_nested_fields(fields)
# Drop any fields that are not specified in the `fields` argument.
select_nested_fields(self, fields)