Reputation: 3089
I building a project in Django that needs to list all fields from a given model as options of a html select tag. I wrote a recursive function that reads the model and returns a list with all fields and subfields. Like this:
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
It returns an object such as the following:
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'
]
However, I need to get a single level list which would look like this:
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'
]
I couldn't write a recursive function to return such result. Do you have any ideas on how to perform this task? I'm stuck on this function below. But it does not behave as expected.
PS.: list_fields
argument will come from the get_fields_true_hierarchy()
function.
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
Upvotes: 1
Views: 823
Reputation: 77912
Use a recursive generator instead, and prefix the names on the fly:
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
Upvotes: 4