使用CKAN API和Python请求库创建CKAN数据集

使用CKAN API和Python请求库创建CKAN数据集,python,python-requests,ckan,Python,Python Requests,Ckan,我使用的是CKAN版本2.2,并尝试自动创建数据集和上传资源。我似乎无法使用python请求库创建数据集。我收到400个错误代码。代码: import requests, json dataset_dict = { 'name': 'testdataset', 'notes': 'A long description of my dataset', } d_url = 'https://mywebsite.ca/api/action/package_create' auth

我使用的是CKAN版本2.2,并尝试自动创建数据集和上传资源。我似乎无法使用python请求库创建数据集。我收到400个错误代码。代码:

import requests, json

dataset_dict = {
    'name': 'testdataset',
    'notes': 'A long description of my dataset',
}

d_url = 'https://mywebsite.ca/api/action/package_create'
auth = {'Authorization': 'myKeyHere'}
f = [('upload', file('PathToMyFile'))]

r = requests.post(d_url, data=dataset_dict, headers=auth)
奇怪的是,我能够使用python请求库创建一个新资源并上传一个文件。该代码基于以下代码:

我还能够使用CKAN文档中使用内置python库的方法创建数据集。文件:

代码:

我不确定为什么我创建数据集的方法不起作用。package_create和resource_create函数的文档非常相似,我希望能够使用相同的技术。我更愿意在与CKAN的所有交易中使用请求包。是否有人能够使用请求库成功创建数据集


非常感谢您的帮助。

您发送的数据必须是JSON编码的

从文档(链接到的页面)中:

要调用CKAN API,请在HTTP post请求中发布JSON字典 到CKAN的API URL之一

在urllib示例中,这由以下代码行执行:

data_string = urllib.quote(json.dumps(dataset_dict))
我认为(尽管您应该检查一下)
请求
库将为您进行报价-因此您只需要将dict转换为JSON。像这样的方法应该会奏效:

r = requests.post(d_url, data=json.dumps(dataset_dict), headers=auth)

我终于回到这一点上,找到了答案。艾丽斯建议检查编码,这一点非常接近。虽然请求确实为您进行编码,但它也会根据输入自行决定哪种类型的编码是合适的。如果文件与JSON字典一起传入,请求会自动执行多部分/表单数据编码,该编码被CKAN接受,因此请求成功

但是,如果我们只传递一个JSON字典,那么默认编码是表单编码。CKAN需要对没有文件的请求进行URL编码(application/x-www-form-urlencoded)。为了防止请求进行任何编码,我们可以将参数作为字符串传入,然后请求将只执行POST。这意味着我们必须自己对其进行URL编码

因此,如果指定内容类型,请将参数转换为字符串并使用urllib编码,然后将参数传递给请求:

head['Content-Type'] = 'application/x-www-form-urlencoded'
in_dict = urllib.quote(json.dumps(in_dict))
r = requests.post(url, data=in_dict, headers=head)

然后请求成功。

感谢您的回复。根据请求文档中的样本,它会为您进行报价。但是,将字典转换为json然后传入也不起作用。同样的问题。但我并不感到惊讶,因为如果是这种情况,我希望在创建资源时会出现相同的错误,但资源创建工作与我的第二个示例相同。谢谢你的努力!:)谢谢你发布这个。我永远也弄不明白。耶苏
r = requests.post(d_url, data=json.dumps(dataset_dict), headers=auth)
head['Content-Type'] = 'application/x-www-form-urlencoded'
in_dict = urllib.quote(json.dumps(in_dict))
r = requests.post(url, data=in_dict, headers=head)