Okay, so you folks may remember variablesdecode() from formencode. I
said it wasn't good for any client-side javascript there too. I wasn't
just saying that because I was whining -- I wrote a filter that will
convert form variables with names like "foo.bar.baz" into full fledged
dictionaries and lists.
I even tested it on a TG server, so it should work :).
Example #1:
>>> print _nestedList({'company': 'Unexistential Inc',
'names.firstName': ['Joe', 'Boe', 'Moe'],
'names.lastName': ['Smith', 'Myth', 'Keith'],
'phone': '555-8980'})
>>> { 'company' : 'Unexistential Inc',
'names' : [{'firstName' : 'Joe', 'lastName' : 'Smith'},
{'firstName' : 'Boe', 'lastName' : 'Myth'},
{'firstName' : 'Moe', 'lastName' : 'Keith'}],
'phone' : '555-8980' }
####
####
class NestedListFilter(BaseFilter):
"""
Will build a nested list for request params with periods in the
name,
for an example look at _nestedList().
"""
def beforeMain(self):
cherrypy.request.paramMap =
self._nestedList(cherrypy.request.paramMap)
def _nestedList(self, oldDict):
"""
Given a dictionary with keys like 'foo.bar.joo' : [oldValue1,
oldValue2],
this will return a new tree with a key of
foo : [{ 'bar': {'joo' : oldValue1}}, { 'bar': {'joo' :
oldValue2}}],
for every key.
Example #1:
>>> print self._nestedList({'company': 'Unexistential Inc',
'names.firstName': ['Joe', 'Boe', 'Moe'],
'names.lastName': ['Smith', 'Myth',
'Keith'],
'phone': '555-8980'})
>>> { 'company' : 'Unexistential Inc',
'names' : [{'firstName' : 'Joe', 'lastName' : 'Smith'},
{'firstName' : 'Boe', 'lastName' : 'Myth'},
{'firstName' : 'Moe', 'lastName' : 'Keith'}],
'phone' : '555-8980' }
Example #2
>>> print self._nestedList(
{'misc': 'Trespassing Prohibited!',
'top.locations.state': ['IL', 'NY'],
'top.locations.zip': [48890, 21142],
'top.markets': ['Belmont', 'Reasan']}
)
>>> {'misc': 'Trespassing Prohibited!',
'top': [{'markets': 'Belmont', 'locations':
{'state': 'IL', 'zip': 48890}},
{'markets': 'Reasan', 'locations':
{'state': 'NY', 'zip': 21142}}
]}
"""
y = {}
for oldKey, oldValue in oldDict.iteritems():
splitList = oldKey.split(".")
if len(splitList) > 1: #there was a period in the key
if type(oldValue) != list:
forceValue = [oldValue] #force to be a list
else:
forceValue = oldValue
key = splitList[0]
#print "Fixing %s with %s" %(str(oldKey),
str(forceValue))
#create list indices if necessary, since we'll be using
them
if y.get(key, None) == None:
#y[key] = [None]*len(forceValue)
y[key] = [dict() for i in range(len(forceValue))]
#print "%s wasn't found, so we padded it %d times"
%(str(key), len(forceValue))
#print y[key]
elif len(y[key]) < len(forceValue):
#y[key][len(y[key]):] = [None]*len(forceValue) #pad
list if necessary
y[key][len(y[key]):] = \
[dict() for i in range(len(forceValue) -
len(y[key]))]
#print "%s was too short, so we padded it %d times"
%(str(key), len(forceValue) - len(y[key]))
#print y[key]
for index, realValue in enumerate(forceValue):
#start = y[key][index]
if type(y[key][index]) != dict: #will be dict from
earlier
y[key][index] = {}
start = y[key][index]
if type(start) != dict:
print "%s not a dict, making {}"
%str(start)
else: #none
print "%s isn't there, making {}"
%str(start)
else:
start = y[key][index]
#print "Starting %s on %d with %s" %(str(start),
index, str(realValue))
#drop down and create dictionaries
for nestKey in splitList[1:-1]:
if type(start) != dict or \
start.get(nestKey, None)
== None:
#if type(start) != dict:
#print "%s not a dict, making {}"
%str(start)
#else: #none
#print "%s isn't there, making {}"
%str(start)
start[nestKey] = {}
#overwrite old non-dict values if necessary
#else:
#print "%s is there, dropping down"
%str(start)
start = start[nestKey]
#drop down to a deeper level
if type(start) == dict:
old_old = start.get(splitList[-1], None)
else:
old_old = None
#print "Dropping %s down to %s with %s and setting
to %s" %(
# str(start), str(old_old), str(splitList[-1]),
str(realValue) )
if type(start) != dict:
start = { splitList[-1] : realValue}
else:
start[splitList[-1]] = realValue
#print "Finished y[%s][%s] and now its %s"
%(str(key), str(index), str(y[key][index]))
#print "Entire y[%s] is %s" %(str(key),
str(y[key]))
#print
#print
#print
else: #regular dict member, just go ahead and add it
y[oldKey] = oldValue
return y