在Python中解析类似字典的URL参数

10

我正在使用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所代表的对象,但在规范中,我找不到这种数据结构的规定。
我开始编写一个函数,以接受参数字典并返回它们表示的嵌套结构,但很快我意识到这是一个微妙的问题,肯定有人曾经遇到过这个问题。
是否有人知道任何可以按照我想要的方式解析这些参数的模块,或者我可能忽略了的优雅解析方法?

1
必须使用GET参数吗?JSON格式不好吗? - Jimmy Kane
1
可能是重复的问题,参考链接:https://dev59.com/kmsz5IYBdhLWcg3wYGoz - Nick ODell
嗯,kendoUI的Grid默认尝试使用GET参数。你可能能够覆盖它,但这似乎也会破坏RESTful范例 - 发送JSON需要一个POST,而你并没有更新任何东西,只是获取一系列项目。(我可能完全错了,所以请随意纠正我) - Lyndsy Simon
@NickODell 是的,那似乎是同样的问题,而我在搜索中没有找到那个。不过,这个答案并没有解决我的问题,它只确认了没有标准的方法来解决这个问题。 - Lyndsy Simon
1
KendoUI的Grid控件由一个DataSource对象驱动。DataSource允许通过jQuery的$.ajax方法配置如何进行CRUD操作。看起来我可以使用JSON。不过,这似乎是Python中很有用的东西,因为显然PHP和RoR都可以处理在查询字符串中传递的嵌套字典。 - Lyndsy Simon
3个回答

9
我刚刚写了一个小函数来实现这个功能:
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)

这应该适用于任何嵌套级别。


不错,经过仔细查看,它应该适用于大多数情况。仍然有一些情况,查询应该返回列表而不是字典,但+1。 - Tadeck
最终,我选择了一个现成的库而不是自己构建 - 但由于“手动操作”是我最终采用的方法,所以我接受了你的答案。供参考,这是我使用的库:https://bitbucket.org/k_bx/jquery-unparam/ - Lyndsy Simon
这太棒了,对于Datatables服务器端的东西非常有效:https://www.datatables.net/manual/server-side。我希望人们在编写他们的ajax调用时不要假定人们会使用PHP,毕竟现在是2015年。 - migreva
1
这对于查询字符串中的数组是不起作用的,我很困惑为什么Python没有将其内置。 - jshbrntt
@JoshuaBarnett 给我一个例子,我会修复它让它工作! - Nick ODell

4

不久前我发现了这个项目:https://github.com/bernii/querystring-parser

它专门用于实现您想要的功能。

然而,在 PHP 以外的世界中,GET(和POST)参数的行为不同。通常情况下,它们使用多值字典实现。因此,更好的想法可能是适应它或找到与两个世界兼容的方法。

另外,您可以在请求正文(POST)中真正使用JSON序列化数据,并将已访问的资源视为控制器(做某些事情的资源,在这种情况下是搜索某些内容,只需传递一些数据即可)。


然而,在PHP世界之外,GET(和POST)参数的行为有所不同。是的,就像RFC所规定的那样!不幸的是,我只能在手头的工具范围内工作。最终,我找到了一种方法来实现这一点,通过使用第三方库。它很鲜为人知,我打算采用它并适当地打包它。 - Lyndsy Simon
有人明白为什么这不是 urllib.parse.parse_qs 的标准行为吗?! - mecampbellsoup

0

服务器应该假设 GET 请求的正文为空,我认为。 https://dev59.com/C2kv5IYBdhLWcg3w3Ug0 - Lyndsy Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接