在Python中解析字典样式的URL参数
我正在用Python实现服务器端的过滤功能,以支持KendoUI的Grid组件。
我遇到的问题是,默认生成的AJAX调用似乎和Flask自带的URL解析器以及Python的urlparse
模块不兼容。
这里有一个我遇到麻烦的查询字符串的例子:a=b&c=d&foo[bar]=baz&foo[baz]=qis&foo[qis]=bar
我想要的结果是:
{
'a': 'b',
'c': 'd',
'foo': {
'bar': 'baz',
'baz': 'qis',
'qis': bar'
}
}
不幸的是,如果把这个传给Flask的接口,你会得到这样的request.args
:
{
'a': 'b',
'c': 'd',
'foo[bar]': 'baz'
'foo[baz]': 'qis'
'foo[qis]': 'bar'
}
更糟糕的是,实际上,这种结构可能会有好几层。比如,如果你想过滤foo
这一列,只显示值为'bar'
的行,结果会是这样的:
{
'filter[logic]': 'and',
'filter[filters][0][value]': 'bar',
'filter[filters][0][field]': 'foo',
'filter[filters][0][operator]': 'eq'
}
我查阅了相关的标准(RFC),它要求查询字符串只能包含“非层级”的数据。虽然我认为这指的是URI所表示的对象,但在我找到的规范中并没有规定这种数据结构。
我开始写一个函数,想把参数字典转换成它们所代表的嵌套结构,但我很快意识到这是个复杂的问题,肯定有人之前也遇到过这个麻烦。
有没有人知道有没有模块可以按照我想要的方式解析这些参数,或者有没有我可能忽略的优雅解析方法?
3 个回答
你也可以在GET请求中发送数据。如果你需要发送的只是一些层次结构的数据,可以在客户端用json.dumps(data)把数据转换成JSON格式,然后在服务器端用json.loads(data)把它转换回来。
你可以在httplib的文档中查看相关的做法,链接在这里: http://docs.python.org/2/library/httplib.html#httplib.HTTPConnection.request
不久前,我发现了这个项目:https://github.com/bernii/querystring-parser
这个项目正好是为了满足你的需求而设计的。
不过,在PHP以外的环境中,GET和POST参数的处理方式是不同的。通常,它们会用多值字典来实现。所以,可能更好的办法是适应这种方式,或者找到一种能兼容两种环境的方法。
另外,你也可以在请求体中使用JSON格式的数据(POST),然后把访问的资源当作控制器来处理(这个资源会在你传递一些数据后执行某些操作,比如搜索东西)。
我刚写了一个小函数来完成这个任务:
from collections import defaultdict
import re
params = {
'a': 'b',
'c': 'd',
'foo[bar]': 'element1',
'foo[baz]': 'element2',
'foo[qis]': 'element3',
'foo[borfarglan][bofgl]': 'element4',
'foo[borfarglan][bafgl]': 'element5',
}
def split(string, brackets_on_first_result = False):
matches = re.split("[\[\]]+", string)
matches.remove('')
return matches
def mr_parse(params):
results = {}
for key in params:
if '[' in key:
key_list = split(key)
d = results
for partial_key in key_list[:-1]:
if partial_key not in d:
d[partial_key] = dict()
d = d[partial_key]
d[key_list[-1]] = params[key]
else:
results[key] = params[key]
return results
print mr_parse(params)
这个函数应该可以处理任何嵌套的层级。