【问题标题】:Targeting specific values from JSON API and inserting into Postgresql, using Python使用 Python 从 JSON API 定位特定值并插入 Postgresql
【发布时间】:2019-04-29 12:59:24
【问题描述】:

现在我可以连接到 url api 和我的数据库。我正在尝试使用 psycopg2 将数据从 url 插入到 postgresql 数据库。我不完全理解如何做到这一点,这就是我能想到的。

import urllib3
import json
import certifi
import psycopg2
from psycopg2.extras import Json


http = urllib3.PoolManager(
    cert_reqs='CERT_REQUIRED',
    ca_certs=certifi.where())
url = '<API-URL>'
headers = urllib3.util.make_headers(basic_auth='<user>:<passowrd>')
r = http.request('GET', url, headers=headers)
data = json.loads(r.data.decode('utf-8'))


def insert_into_table(data):

    for item in data['issues']:
        item['id'] = Json(item['id'])

    with psycopg2.connect(database='test3', user='<username>', password='<password>', host='localhost') as conn:
        with conn.cursor() as cursor:
            query = """
                INSERT into
                     Countries
                    (revenue)
                VALUES
                    (%(id)s);
            """
            cursor.executemany(query, data)

        conn.commit()


insert_into_table(data)

所以这段代码在cursor.executemany(query, data)上给我一个TypeError: string indices must be integers

所以我知道 json.loads 带回了一个类型对象,而 json.dumps 带回了一个类型字符串。我不确定我应该使用哪一个。而且我知道我完全错过了关于我如何定位“id”值并将其插入查询的内容。

还有一点关于 API,它非常庞大且复杂,最终我将不得不向下多棵树来获取某些值,这是我从中提取的一个示例。

我试图在“问题”而不是“问题类型”下获取“id”

{
  "expand": "<>",
  "startAt": 0,
  "maxResults": 50,
  "total": 13372,
  "issues": [
    {
      "expand": "<>",
      "id": "41508",
      "self": "<>",
      "key": "<>",
      "fields": {
        "issuetype": {
          "self": "<>",
          "id": "1",
          "description": "<>",
          "iconUrl": "<>",
          "name": "<>",
          "subtask": <>,
          "avatarId": <>
        },

【问题讨论】:

    标签: python json python-3.x postgresql psycopg2


    【解决方案1】:

    首先,将ids 提取到一个元组列表中:

    ids = list((item['id'],) for item in data['issues'])
    # example ids: [('41508',), ('41509',)]
    

    接下来使用函数extras.execute_values():

    from psycopg2 import extras
    
    query = """
        INSERT into Countries (revenue)
        VALUES %s;
    """
    extras.execute_values(cursor, query, ids)
    

    为什么会出现类型错误?

    函数executemany(query, vars_list)的第二个参数应该是一个序列,而data是一个对象,它的元素不能被整数索引访问。

    为什么要使用execute_values() 而不是executemany()

    由于性能原因,第一个函数执行带有多个参数的单个查询,而第二个函数执行与参数一样多的查询。

    注意,默认情况下execute_values()的第三个参数是一个元组列表,所以我们就是这样提取ids的。

    如果您必须在多列中插入值,则列表中的每个元组都应包含单个插入行的所有值,例如:

    values = list((item['id'], item['key']) for item in data['issues'])
    
    query = """
        INSERT into Countries (id, revenue)
        VALUES %s;
    """
    extras.execute_values(cur, query, values)
    

    【讨论】:

    • 那行得通,但你能解释一下答案以及为什么我会遇到类型错误吗?
    • 如果我要添加另一个值,比如说INSERT into table (title, revenue) VALUES (%s, %s),然后通过执行keys= list((item['key'],) for item in data['issues']) 添加键值,然后创建一个变量result = [ids, keys],我是否能够传递“结果”而不是execute_values() 函数中的 'ids' 将标题列中的 'id' 和收入列中的 'keys' 传递?
    • 当我进行这些更改时,我收到此错误psycopg2.ProgrammingError: INSERT has more expressions than target columns 这是因为唯一的占位符%s?我意识到execute_many() 只允许一个占位符,所以这与我的实际表模式有关吗?
    • 不,我的 sql 语句中有这个
    • 哦,知道了,不小心在 %s 占位符周围加上了括号,再次感谢!
    【解决方案2】:

    如果您只是想获取 id 并将其插入到您的表格中,您应该尝试

    ids = []
    for i in data['issues']:
         ids.append(i['id'])
    

    然后您可以将您的ids 列表传递给您的cursor.executemany 函数。

    【讨论】:

    • 所以cursor.executemany(query, ids)?以及您所做的更改?
    【解决方案3】:

    您遇到的问题不在于您解析 JSON 的方式,而是在您尝试使用 cursor.executemany() 将其插入表中时发生。

    data 是单个对象,您是否尝试将您的 fetch 返回的所有数据一次全部插入到您的表中?或者您是否尝试插入数据的特定部分(问题 ID 列表)?

    您正在将data 传递给您的cursor.executemany 调用。 data 是一个对象。我相信您希望通过data.issues 这是您修改的问题列表。

    如果您只想将 id 插入表中,请尝试以下操作:

    def insert_into_table(data):
    
        with psycopg2.connect(database='test3', user='<username>', password='<password>', host='localhost') as conn:
            with conn.cursor() as cursor:
                query = """
                INSERT into
                     Countries
                    (revenue)
                VALUES
                    (%(id)s);
                """
                for item in data['issues']:
                   item['id'] = Json(item['id'])
                   cursor.execute(query, item['id')
    
                conn.commit()
    
    
    insert_into_table(data)
    

    如果您希望保持使用cursor.executemany() 的效率,您需要创建一个ID 数组,因为当前对象结构没有按照cursor.executemany() 要求的方式排列它们。

    【讨论】:

    • 好吧,这确实有道理,现在我收到一条错误消息,说 executemany 函数中的 Json 对象 item['id'] 不是“可迭代”
    • 请注意 execute()executemany() 采用不同的参数。如果你想使用executemany(),你需要创建你自己传递给函数的id数组。这有意义吗?
    猜你喜欢
    • 2015-12-25
    • 2021-04-21
    • 2017-12-31
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    • 2022-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多