【问题标题】:How to create HTTP-request data with {single key:multi values} [duplicate]如何使用 {single key:multi values} 创建 HTTP 请求数据 [重复]
【发布时间】:2016-10-27 00:24:22
【问题描述】:

我需要发送HTTP POST 请求,数据如下:

data = {'id[]': '1', 'id[]': '2', 'id[]': '3'}

Values 列表实际上是未知的,但让它成为values_list = ['1', '2', '3']

当然可以试试

for value in values_list:
    data["id[]"] = value

我得到{'id[]': '3'},因为每次迭代都会覆盖键值对...

我用this解决方案:

data = {}

class data_keys(object):
    def __init__(self, data_key):
        self.data_key = data_key

for value in values_list:
    data[data_keys('id[]')] = value

但我的data 看起来像

{<__main__.data_keys object at 0x0000000004BAE518>: '2',
 <__main__.data_keys object at 0x0000000004BAED30>: '1',
 <__main__.data_keys object at 0x0000000004B9C748>: '3'}

我的代码有什么问题?我还能如何简单地用单键创建字典?

更新

这就是我的HTTP 请求的样子:

requests.post(url, data={"id[]": '1', "id[]": '2', "id[]": '3'}, auth=HTTPBasicAuth(user_name, user_passw))

标题更新

【问题讨论】:

  • 您的意思是创建一个字典,其中同一个键出现多次?你不能,像dict 这样的哈希映射要求每个键只出现一次。
  • 字典中的每个键都必须不同(不同的哈希)才能被访问,即:如果你有d = {'a':1,'a':2}d['a'] 会是什么?
  • 对于所有评论的人来说,这个问题有点令人费解和误导,但它显然不是关于创建具有重复键的字典,而只是关于使用某种固定形式的序列化数据创建 HTTP 请求。第二个在技术上是可行的,而无需创建具有重复键的字典(这显然是不可能的)。为什么需要这种形式 - 我不确定,但据我们所知,我们可能会假设服务器已损坏 API 并且 OP 无法更改它...
  • 我想您可能会发现帖子数据是一个带有值列表的id键,您可以分享链接吗?
  • @PadraicCunningham 是的,这很可能。那么,另一个XY Problem

标签: python python-2.7 python-3.x dictionary python-requests


【解决方案1】:

虽然您可以破解字典键以允许看似“相等”的键,但这可能不是一个好主意,因为这依赖于键如何转换为字符串的实现细节.此外,如果您需要调试这种情况,肯定会引起混乱。

form data encode mechanism 中实际上内置了一个更简单且受支持的解决方案:您可以简单地传递值列表:

data = {
    'id[]': ['1', '2', '3']
}

req = requests.get(url='http://www.example.com', params=data)
print(req.url) # 'http://www.example.com/?id%5B%5D=1&id%5B%5D=2&id%5B%5D=3'

因此,您只需将values_list 直接传递到字典中,一切都会正常运行,而无需破解任何东西。


如果您发现自己处于认为这样的字典不起作用的情况,您还可以提供双元组的可迭代(第一个值是键,第二个是值):

data = [
    ('id[]', '1'),
    ('id[]', '2'),
    ('id[]', '3')
]

req = requests.get(url='http://www.example.com', params=data)
print(req.url) # 'http://www.example.com/?id%5B%5D=1&id%5B%5D=2&id%5B%5D=3'

【讨论】:

  • 终于有理性的声音了。 :)
【解决方案2】:

为了让你的data_keys 类做你想做的事,你需要给它一个合适的__repr____str__ 方法。这将允许在您打印 dict 或其他一些代码尝试序列化它时以所需的方式显示类实例。

这是一个使用 3rd 方请求模块构建 URL 的简短演示。我更改了类名以使其符合通常的 Python 类命名约定。此代码已在 Python 2.6 和 Python 3.6 上测试

from __future__ import print_function
import requests

class DataKey(object):
    def __init__(self, data_key):
        self.data_key = data_key

    def __repr__(self):
        return str(self.data_key)

data = {}
values_list = ['1', '2', '3']

for value in values_list:
    data[DataKey('id[]')] = value

print(data)

req = requests.get(url='http://www.example.com', params=data)
print(req.url)

输出

{id[]: '1', id[]: '2', id[]: '3'}
http://www.example.com/?id%5B%5D=1&id%5B%5D=2&id%5B%5D=3

这是一个受json 模块可接受的 Rogalski 答案启发的更强大的版本,.

from __future__ import print_function
import requests
import json

class DataKey(str):
    def __init__(self, data_key):
        self.data_key = data_key

    def __repr__(self):
        return str(self.data_key)

    def __eq__(self, other):
        return self is other

    def __hash__(self):
        return id(self)

data = {}
values_list = ['1', '2', '3']

for value in values_list:
    data[DataKey('id[]')] = value

print(data)

req = requests.get(url='http://www.example.com', params=data)
print(req.url)

print(json.dumps(data))

输出

{id[]: '3', id[]: '1', id[]: '2'}
http://www.example.com/?id%5B%5D=3&id%5B%5D=1&id%5B%5D=2
{"id[]": "3", "id[]": "1", "id[]": "2"}

正如我在对该问题的评论中提到的,这很奇怪,并且创建具有多个(伪)相同键的字典确实不是一件非常有用的事情。几乎总会有更好的方法,例如使用列表或元组的dict,或者在这种情况下,提供数据的另一种方法,如 Poke 的回答所示。

但是,我应该提一下,在 JSON 对象中禁止多个相同的键,因此有时可能需要处理此类 JSON 数据。我声称使用这些疯狂的字典是一种很好的方法,但它一种可能性......

【讨论】:

  • 哇,有趣,内置的json 模块要求字典键是basestring 子类。 requests 内部使用什么来序列化有效载荷?
  • @Rogalski:我不知道requests 在做什么黑魔法。坦率地说,我有点惊讶requests 没有好好抱怨。 :)
  • 哦,id 比显式计数器干净得多,很好。做得很好。
  • requests.get(url='http://www.example.com', params={"id[]":['1', '2', '3']}) 会给你完全相同的输出,我认为 OP 实际上并不完全了解发布请求所需的内容。
  • OP 的困惑很可能来自这样一个事实,即当您在 firebug 或 chrome 工具中监视发布请求时,您会看到 id[]:1 id[]:2 id[]:3 等作为单独的发布参数,可以有点混乱,我没有发布答案,因为虽然它是正确的解决方案,但它与标题并不完全一致,实际上也有很多骗子。
【解决方案3】:

不要在实际代码中这样做,但基本结构应该是这样的:

data = {}
values_list = [1,2,3]

class data_keys(str):
    unique = 0
    def __init__(self, val):
        super(data_keys, self).__init__(val)
        self.unique += 1
        self.my_hash = self.unique
    def __eq__(self, other):
        return False
    def __hash__(self):
        return self.my_hash


for value in values_list:
    data[data_keys('id[]')] = value

print json.dumps(data)
# '{"id[]": 1, "id[]": 3, "id[]": 2}'

如您所见,关键对象必须继承自 basestring 类。我用过str。此外,还有一个肮脏的 hack(类变量)来确保任何一对 data_keys 之间的唯一哈希和不等式。

只是概念证明,当然可以做得更好。

【讨论】:

  • 干得好。我想我应该更新我的答案,以便它也适用于 JSON。 ;)
猜你喜欢
  • 2021-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-04
  • 1970-01-01
相关资源
最近更新 更多