Django:将模型字段递归(ForeignKeys及其字段)作为字符串放入1级列表中

时间:2015-03-31 10:24:55

标签: python django algorithm recursion

我在Django中构建一个项目,需要列出给定模型中的所有字段作为html选择标记的选项。 我写了一个递归函数,它读取模型并返回包含所有字段和子字段的列表。像这样:

def get_fields_true_hierarchy(model, list_fields = []):
    fields_obj = model._meta.fields
    for field_obj in fields_obj:
        if field_obj.rel:
            dict_fields = {field_obj.attname: []}
            list_fields.append(dict_fields)
            get_fields_true_hierarchy(field_obj.rel.to, dict_fields[field_obj.attname])
        else:
            list_fields.append(field_obj.attname)
    return list_fields

返回如下对象:

fiedls = [
    'id', 
    'title', 
    'number', 
    'start_date', 
    'finish_date', 
    {'status_id':
        ['id', 
        'name']
    }, 
    'postal_code', 
    {'requestor_id': 
        ['id', 
        {'user_id': 
            ['id', 
            'password', 
            'last_login', 
            'is_superuser', 
            'username', 
            'first_name', 
            'last_name', 
            'email', 
            'is_staff', 
            'is_active', '
            date_joined']
        }, 
        'name', 
        'phone', 
        'email',  
        'contact_name', 
        'contact_email']
    }, 
    {'reason_id': 
        ['id', 
        'description']
    }, 
    'details', 
    {'group_id': 
        ['id', 
        'description']
    }, 
    {'subgroup_id': 
        ['id', 
        'description']
    }, 
    {'manager_id': 
        ['id', 
        'password', 
        'last_login', 
        'is_superuser', 
        'username', 
        'first_name', 
        'last_name', 
        'email', 
        'is_staff', 
        'is_active', 
        'date_joined']
    }, 
    'datetime_subscription', 
    'allowed', 
    'data_def'
]

但是,我需要获得一个单一级别的列表,如下所示:

fiedls = [
    'id', 
    'title', 
    'number', 
    'start_date', 
    'finish_date', 
    'status_id',
    'status_id.id', 
    'status_id.name', 
    'postal_code', 
    'requestor_id',
    'requestor_id.id', 
    'requestor_id.user_id',
    'requestor_id.user_id.id', 
    'requestor_id.user_id.password', 
    'requestor_id.user_id.last_login', 
    'requestor_id.user_id.is_superuser',
    'requestor_id.user_id.username', 
    'requestor_id.user_id.first_name', 
    'requestor_id.user_id.last_name', 
    'requestor_id.user_id.email', 
    'requestor_id.user_id.is_staff', 
    'requestor_id.user_id.is_active',
    'requestor_id.user_id.date_joined',
    'requestor_id.name', 
    'requestor_id.phone', 
    'requestor_id.email',  
    'requestor_id.contact_name', 
    'requestor_id.contact_email',
    'reason_id',
    'reason_id.id', 
    'reason_id.description',
    'details',
    'group_id', 
    'group_id.id', 
    'group_id.description',
    'subgroup_id',
    'subgroup_id.id', 
    'subgroup_id.description',
    'manager_id', 
    'manager_id.id',
    'manager_id.password', 
    'manager_id.last_login', 
    'manager_id.is_superuser', 
    'manager_id.username', 
    'manager_id.first_name', 
    'manager_id.last_name', 
    'manager_id.email', 
    'manager_id.is_staff', 
    'manager_id.is_active', 
    'manager_id.date_joined',
    'datetime_subscription', 
    'allowed',
    'data_def'
]

我无法写一个递归函数来返回这样的结果。您对如何执行此任务有任何想法吗? 我坚持下面的这个功能。但它的行为并不像预期的那样。

PS。:list_fields参数将来自get_fields_true_hierarchy()函数。

def get_fields_fake_hierarchy(list_fields, fake_hierarchy = [], parent_str = "", reset=True):
    for field in list_fields:
        if reset:
            parent_str = ""
        if isinstance(field, dict):
            for key, value in field.iteritems():
                fake_hierarchy.append(key)
                parent_str += "."+key
                get_fields_fake_hierarchy(value, fake_hierarchy, parent_str, reset=False)
        else:
            fake_hierarchy.append("%s.%s"%(parent_str, field))
    fake_hierarchy = [i[1:] if i[0]=='.' else i for i in fake_hierarchy]
    return fake_hierarchy

1 个答案:

答案 0 :(得分:3)

改为使用递归生成器,并在运行时为名称添加前缀:

def do_prefix(name, prefix):
    if prefix:
        return "%s.%s" % (prefix, name)
    return name

def get_fields_flat(model):
    return [name for name in iter_fields(model)]

def iter_fields(model, prefix=None):
    fields = model._meta.fields
    for field in fields:
        name = do_prefix(field.attname, prefix)
        yield  name
        if field.rel:
            rel = field.rel.to
            for f in iter_fields(rel, name):
                yield f