psycopg2 插入 python 字典作为 json

psycopg2 insert python dictionary as json

我想将 python 字典作为 json 插入到我的 postgresql 数据库中(通过 python 和 psycopg2)。

我有:

thedictionary = {'price money': '', 'name': 'Google', 'color': '', 'imgurl': 'http://www.google.com/images/nav_logo225.png', 'charateristics': 'No Description', 'store': 'google'}

cur.execute("INSERT INTO product(store_id, url, price, charecteristics, color, dimensions) VALUES (%d, %s, %s, %d, %s, %s)", (1,  'http://www.google.com', '', thedictionary, 'red', '8.5x11'))

它给出了错误信息:

cur.execute("INSERT INTO product(store_id, url, price, charecteristics, color, dimensions) VALUES (%d, %s, %s, %d, %s, %s)", (1, 'http://www.google.com', '', thedictionary, 'red', '8.5x11')) psycopg2.ProgrammingError: can't adapt type 'dict'

我不确定如何从这里开始。 我在互联网上找不到任何关于如何做这种事情的信息,而且我对 psycopg2 还很陌生。

cur.execute("INSERT INTO product(store_id, url, price, charecteristics, color, dimensions) VALUES (%s, %s, %s, %s, %s, %s)", (1,  'http://www.google.com', '', json.dumps(thedictionary), 'red', '8.5x11'))

这将解决您的问题。但是,您确实应该将键和值存储在它们自己单独的列中。要检索字典,请执行:

cur.execute('select charecteristics from product where store_id = 1')
dictionary = json.loads(cur.fetchone()[0])

您可以使用 psycopg2.extras.Json 将 dict 转换为 postgre 接受的 json。

from psycopg2.extras import Json

thedictionary = {'price money': '', 
'name': 'Google', 'color': '', 'imgurl': 'http://www.google.com/images/nav_logo225.png', 'charateristics': 'No Description', 'store': 'google'}

item ={
    "store_id":1,
    "url": 'http://www.google.com', 
    "price":'', 
    "charecteristics":Json(thedictionary), 
    "color":'red', 
    "dimensions":'8.5x11'
}

def sql_insert(tableName, data_dict):
    '''
    INSERT INTO product (store_id,  url,  price,  charecteristics,  color,  dimensions)
    VALUES (%(store_id)s, %(url)s, %(price)s, %(charecteristics)s, %(color)s, %(dimensions)s );
    '''
    sql = '''
        INSERT INTO %s (%s)
        VALUES (%%(%s)s );
        '''   % (tableName, ',  '.join(data_dict),  ')s, %('.join(data_dict))
    return sql

tableName = 'product'
sql = sql_insert(tableName, item)

cur.execute(sql, item)

更多信息,您可以查看the official document

class psycopg2.extras.Json(adapted, dumps=None)

    An ISQLQuote wrapper to adapt a Python object to json data type.

    Json can be used to wrap any object supported by the provided dumps function. If none is provided, the standard json.dumps() is used (simplejson for Python < 2.6; getquoted() will raise ImportError if the module is not available).

    dumps(obj)
    Serialize obj in JSON format.

    The default is to call json.dumps() or the dumps function provided in the constructor. You can override this method to create a customized JSON wrapper.

来自psycopg docs

Note You can use register_adapter() to adapt any Python dictionary to JSON, either registering Json or any subclass or factory creating a compatible adapter:

psycopg2.extensions.register_adapter(dict, psycopg2.extras.Json)

This setting is global though, so it is not compatible with similar adapters such as the one registered by register_hstore(). Any other object supported by JSON can be registered the same way, but this will clobber the default adaptation rule, so be careful to unwanted side effects.

因此,就我而言,我所做的是:

from psycopg2.extensions import register_adapter

register_adapter(dict, Json)

它就像一个魅力。

您是否有特殊原因希望将每个键作为自己的列? Postgres 允许您在包含有效 JSON 或 JSONB

的单个列中执行直接查询操作

这意味着您可以简单地创建一个包含 ID(主键)和元数据的 2 列数据库,然后执行查询,例如:

SELECT * FROM users WHERE metadata @> '{"key": "value"}';

Here 对您来说是一个很好的资源。

将dict类型转换为json_str即可,使用json.dumps(adict).

import pandas as pd
import json
import psycopg2
from sqlalchemy import create_engine
engine_nf = create_engine('postgresql+psycopg2://user:password@192.168.100.120:5432/database')
sql_read = lambda sql: pd.read_sql(sql, engine_nf)
sql_execute = lambda sql: pd.io.sql.execute(sql, engine_nf)

sql = '''
CREATE TABLE if not exists product (
    store_id  int
    , url  text
    , price text
    , charecteristics json
    , color text
    , dimensions text
)
'''
_ = sql_execute(sql)

thedictionary = {'price money': '', 'name': 'Google', 
    'color': '', 'imgurl': 'http://www.google.com/images/nav_logo225.png', 
    'charateristics': 'No Description', 
    'store': 'google'}

sql = '''
INSERT INTO product(store_id, url, price, charecteristics, color, dimensions) 
VALUES (%d, '%s', '%s', '%s', '%s', '%s')
''' % (1, 'http://www.google.com', '', 
       json.dumps(thedictionary), 'red', '8.5x11')

sql_execute(sql)

sql = '''
select * 
from product
'''
df = sql_read(sql)
df
    #   store_id    url price   charecteristics color   dimensions
    # 0 1   http://www.google.com    {'price money': '', 'name': 'Google', 'color...   red 8.5x11

charecteristics = df['charecteristics'].iloc[0]
type(charecteristics)
    # dict

事实上,我喜欢另一种将数据转储到 postgres 的方法。

import io
import csv
def df2db(df_a, table_name, engine):
    output = io.StringIO()
    # ignore the index
    df_a.to_csv(output, sep='\t', index = False, header = False, quoting=csv.QUOTE_NONE)
    output.getvalue()
    # jump to start of stream
    output.seek(0)

    #engine ---- from sqlalchemy import create_engine
    connection = engine.raw_connection() 
    cursor = connection.cursor()
    # null value become ''
    cursor.copy_from(output,table_name,null='')
    connection.commit()
    cursor.close()


df = sql_read('select * from product')
type(df.charecteristics.iloc[0])
df.charecteristics = df.charecteristics.map(json.dumps)

# dump pandas DataFrame to postgres
df2db(df, 'product', engine_nf)
df_end = sql_read('select * from product')

首先,该错误意味着您正试图将 dict 值推入无法接受它的列类型(TEXT 等 ..)

接受的解决方案是正确的,将它从​​ JSON/dict -> 字符串转换为存储它。

但是,有一个列类型可以接受它:JSON

我建议首先创建一个 JSON 字段以保留类似 dict 的对象。原因是:

  1. 您可以简单地将字典按原样推送到数据库 w/o json.dumps 或其他转换(因为请记住,当您推送时 - 您需要 json.dumps 但是当您 在python中读取它稍后你需要json.loads(从字符串转换回来-> dict)。
  2. 您可以查询它在一个真正的JSON列中的内容,当它是一个字符串时您不能这样做。

https://www.postgresqltutorial.com/postgresql-json/

因此,在创建列时,我建议默认设置 {} vs NULL:

CREATE TABLE my_table (
   ...
   my_json_col JSON default '{}'::JSON
   ...
)

从 psycopg2 2.5 版开始,您可以使用 Json 适配器。

Psycopg can adapt Python objects to and from the PostgreSQL json and jsonb types. With PostgreSQL 9.2 and following versions adaptation is available out-of-the-box.

from psycopg2.extras import Json
curs.execute("insert into mytable (jsondata) values (%s)", [ Json({'a': 100}) ] )

有关详细信息,请参阅文档: https://www.psycopg.org/docs/extras.html#json-adaptation