Django Rest Framework:嵌套的序列化程序动态模型字段 [英] Django Rest Framework : Nested Serializer Dynamic Model Fields

查看:97
本文介绍了Django Rest Framework:嵌套的序列化程序动态模型字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经定义了如下的序列化器。我正在使用 mixin 来更改

  class SerializerTwo(serializers.ModelSerializer):

class Meta:
模型=两个
字段=('name','contact_number')

class SerializerOne(DynamicFieldsModelSerializer,serializers.ModelSerializer):
another_field = SerializerTwo()

类元:
lookup_field ='uuid'
模型=一个
字段=('status','another_field',)

现在我要做的是,动态传递(动态)从SerializerTwo中使用所有字段,就像我对SerializerOne所做的那样。 / p>

我为SerializerOne做的方式是:

 #其中fields =('状态')
SerializerOne(查询集,fields = fields)

是有办法,使用它我可以将SerializerTwo中的字段添加到上面的Serializer初始化中。

 #其中fields =('status','name ')来自SerializerTwo 
#的名称在字段中双下划线表示法不起作用,因此也不能使用another_field__name
SerializerOne(queryset,fields = fields)


解决方案

@Lotram的答案不适用于返回多个值的字段(通过 many = True )。



下面的代码对@Lotram的解决方案进行了改进,该解决方案适用于返回多个值的字段:

  class NestedDynamicFieldsModelSerializer(serializers.ModelSerializer):

def __init __(self,* args,** kwargs):

def parse_nested_fields(fields):
field_object = { fields :: []}
对于字段中的f:
obj = field_object
nested_fields = f.split( __)
for v in nested_fields:
,如果v不在obj [ fields]中:
obj [ fields]。append(v)
如果nested_fields.index(v)< len(nested_fields)-1:
obj [v] = obj.get(v,{ fields:[]})
obj = obj [v]
return field_object

def select_nested_fields(序列化器,字段):
对于字段中的k:
如果k == fields:
fields_to_include(序列化器,字段[k])
其他:
select_nested_fields(serializer.fields [k],fields [k])

def fields_to_include(serializer,fields):
#删除未在中指定的任何字段 fields参数。
允许= set(fields)
如果isinstance(serializer,serializers.ListSerializer):
现有= set(serializer.child.fields.keys())
用于现有的field_name -允许:
serializer.child.fields.pop(field_name)
其他:
现有= set(serializer.fields.keys())
用于现有field_name-允许:
serializer.fields.pop(field_name)

#不要将'fields'arg传递给超类
fields = kwargs.pop('fields',None)
#通常实例化超类
super(NestedDynamicFieldsModelSerializer,self).__ init __(* args,** kwargs)

如果字段不是None:
#import pdb ; pdb.set_trace()
fields = parse_nested_fields(fields)
#删除所有在`fields`参数中未指定的字段。
select_nested_fields(自己,字段)


I have defined serializers like below. I'm using a mixin to change the display fields on the fly.

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',)

Now what I want to do is, dynamically pass(on the fly) what all fields will be used from SerializerTwo, as I'm doing for SerializerOne.

The way I'm doing it for SerializerOne is:

# where fields=('status')
SerializerOne(queryset, fields=fields)

Is there a way, using which I can add fields from SerializerTwo to the above Serializer initialization.

# 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)

解决方案

@Lotram's answer doesn't work on fields that return multiple values (via many=True).

The following code improves upon @Lotram's solution which works on fields that return multiple values:

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)

这篇关于Django Rest Framework:嵌套的序列化程序动态模型字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆