jQuery.param在Python中的反序列化

时间:2018-03-28 20:58:47

标签: python post serialization deserialization

我试图通过jQuery.param()函数反序列化复杂数据。

我找到了python库jquery-unparam,但不幸的是它并没有很好地管理可能发生的那种复杂结构。

我做了一个涵盖所有可能性的例子,这里是数据:

sample = {
    'some': 'value',
    'with': True,
    'but[]': ['contains', 'also', 'some', 'array'],
    'or[0]': 'even',
    'or[1]': 'numbered',
    'or[2]': 'arrays',
    'also[0][some]': 'with',
    'also[0][sub]': 'complex',
    'also[0][values]': 'structure',
    'and[finally]': 'some',
    'and[easier]': 'ones'
}

此数据是Flask中request.form.to_dict()的结果。如果您需要,请按jQuery.param()处理后的原始值:

"some=value&with=true&but%5B%5D=contains&but%5B%5D=also&but%5B%5D=some&but%5B%5D=array&or%5B0%5D=even&or%5B1%5D=numbered&or%5B2%5D=arrays&also%5B0%5D%5Bsome%5D=with&also%5B0%5D%5Bsub%5D=complex&also%5B0%5D%5Bvalues%5D=structure&and%5Bfinally%5D=some&and%5Beasier%5D=ones"

现在,如果您直接从Python库运行代码,您将得到以下结果:

{"and": {"finally": "some", "easier": "ones"}, "some": "value", "but": ["contains", "also", "some", "array"], "also": {"0": {"values": "structure", "some": "with", "sub": "complex"}}, "with": "true", "or": {"1": "numbered", "0": "even", "2": "arrays"}}

问题是,密钥also应该是一个列表,而不是一个字典,它应该是这样的:

{"and": {"finally": "some", "easier": "ones"}, "some": "value", "but": ["contains", "also", "some", "array"], "also": [{"values": "structure", "some": "with", "sub": "complex"}], "with": "true", "or": {"1": "numbered", "0": "even", "2": "arrays"}}

但是我坚持让它成功。

到目前为止我的代码(从库中更改为直接从Flask的to_dict代码开始):

#!/usr/bin/python
# -*- coding: utf-8 -*-

import re, json


def parse_key_pair(key, val):
    groups = re.findall(r"\[.*?\]", key)
    groups_joined =  ''.join(groups)
    if key[-len(groups_joined):] == groups_joined:
        key = key[:-len(groups_joined)]
        for group in reversed(groups):
            if group == '[]':
                val = val
            else:
                # I've implemented this to transform to list, but the result is not good
                try:
                    int(group.replace('[', '').replace(']', ''))
                    val = [val]
                except ValueError:
                    val = {group[1:-1]: val}

    return {key: val}


def merge_two_structs(s1, s2):
    if isinstance(s1, list) and \
       isinstance(s2, list):
        return s1 + s2

    if isinstance(s1, dict) and \
       isinstance(s2, dict):

        retval = s1.copy()
        for key, val in s2.iteritems():
            if retval.get(key) is None:
                retval[key] = val
            else:
                retval[key] = merge_two_structs(retval[key], val)
        return retval
    return s2


def merge_structs(structs):
    if len(structs) == 0:
        return None
    if len(structs) == 1:
        return structs[0]
    first, rest = structs[0], structs[1:]
    return merge_two_structs(first, merge_structs(rest))


def parse_form(pair_strings):
    key_pairs = [parse_key_pair(x, pair_strings[x]) for x in pair_strings]
    return merge_structs(key_pairs)


sample = {
    'some': 'value',
    'with': True,
    'but[]': ['contains', 'also', 'some', 'array'],
    'or[0]': 'even',
    'or[1]': 'numbered',
    'or[2]': 'arrays',
    'also[0][some]': 'with',
    'also[0][sub]': 'complex',
    'also[0][values]': 'structure',
    'and[finally]': 'some',
    'and[easier]': 'ones'
}

print (json.dumps(parse_form(sample)))

如果你可以帮我解决如何获取列表而不是数组的dict,那将是完美的!

当然,如果已经有其他图书馆能够很好地完成这项工作,我全都是耳朵!

1 个答案:

答案 0 :(得分:0)

上面的代码存在问题。

request.form.to_dict()无法正确表示通过"item[]=XXX&item[]=YYY"传递的项目。您只能获得一个item[] ...

所以为了解决这个问题,我已经将to_dict()重写为:

from six import string_types

def convert_val(val):
    if not isinstance(val, string_types):
        return val
    elif val == '':
        return None
    elif val.lower() in ('false', 'true'):
        return True if val.lower() == 'true' else False
    if val[0:1] == '{':
        try:
            return json.loads(val)
        except ValueError:
            pass

    try:
        return int(val)
    except ValueError:
        return val


def request_to_dict(params):
    result = {}
    for k in params:
        items = params.getlist(k)
        if len(items) == 1:
            result[k] = convert_val(items[0])
        else:
            result[k] = items

    return parse_form(result)

这将返回一个正确的字典,解析上述示例的特性,尽可能保留类型(布尔值,整数,json,列表或字符串),并且与Python 2和3兼容。