You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SQLAlchemy与psycopg向PostgreSQL写入DataFrame遇类型适配错误

问题:psycopg2.ProgrammingError: can't adapt type 'dict'

从Kobo Toolbox拉取数据生成DataFrame后,使用SQLAlchemy将数据写入PostgreSQL数据库时触发该错误,其他拉取数据的步骤正常,代码如下:

import psycopg2
import pandas as pd
from sqlalchemy import create_engine
import sqlalchemy
from sqlalchemy.types import String
import pykobo


# establish connections
conn_string = 'postgresql://postgres:openppp@localhost:5432/wpp_appeals'

db = create_engine(conn_string)
conn = db.connect()


URL_KOBO_API = "https://kf.kobotoolbox.org/api/v2"
MYTOKEN = "1e83cdede6c48a19ef210e417d6ca61b076db175"
km = pykobo.Manager(url_api=URL_KOBO_API, token=MYTOKEN)

uid = 'aQCxZ9BVrHe33pLMdtx3gV'
my_form = km.get_form(uid)

    
my_form.fetch_data()  
df1 = my_form.data


df1.to_sql('appeals', con=conn, if_exists='append', index=False, dtype={
    'deviceid':sqlalchemy.String(),
    'TimeStartRecorded':sqlalchemy.VARCHAR(),
    'TimeEndRecorded':sqlalchemy.VARCHAR(),
    'today':sqlalchemy.VARCHAR(),
    'Appeals_Feedback':sqlalchemy.VARCHAR(),
    'Location':sqlalchemy.VARCHAR(),
    'gps_location':sqlalchemy.VARCHAR(),
    '_gps_location_latitude':sqlalchemy.VARCHAR(),
    '_gps_location_longitude':sqlalchemy.VARCHAR(),
    '_gps_location_altitude':sqlalchemy.VARCHAR(),
    '_gps_location_precision':sqlalchemy.VARCHAR(),
    'householdID':sqlalchemy.VARCHAR(),
    'hhNumber':sqlalchemy.VARCHAR(),
    'confirm1':sqlalchemy.VARCHAR(),
    'focalPointName':sqlalchemy.VARCHAR(),
    'validz':sqlalchemy.VARCHAR(),
    '_id':sqlalchemy.VARCHAR(),
    '_uuid':sqlalchemy.VARCHAR(),
    '_submission_time':sqlalchemy.VARCHAR(),
    '_validation_status':sqlalchemy.VARCHAR(),
    '_notes':sqlalchemy.VARCHAR(),
    '_status':sqlalchemy.VARCHAR(),
    '_submitted_by':sqlalchemy.VARCHAR(),
    '_tags':sqlalchemy.VARCHAR(),
    '_index':sqlalchemy.VARCHAR()})

conn = psycopg2.connect(conn_string
                        )

conn.autocommit = True
                     


#conn.commit()
conn.close()

原因分析

Kobo Toolbox返回的DataFrame中存在字典类型的列,尽管你在dtype参数中指定了部分列的类型,但未覆盖所有含dict数据的列,psycopg2无法直接将Python dict类型转换为PostgreSQL支持的原生数据类型,因此触发该错误。

解决方案

1. 定位字典类型列

先运行以下代码找出DataFrame中包含dict数据的列:

for col in df1.columns:
    unique_types = df1[col].apply(type).unique()
    print(f"列名: {col}, 数据类型: {unique_types}")

2. 处理字典类型数据

根据业务需求选择以下方式之一处理:

  • 序列化为JSON字符串:如果需要保留嵌套结构,将dict转为JSON字符串(可存入PostgreSQL的TEXT或JSONB类型):
    import json
    # 替换为实际的字典列名
    df1['Location'] = df1['Location'].apply(lambda x: json.dumps(x) if isinstance(x, dict) else x)
    
  • 直接删除列:如果该列数据无业务价值,直接删除:
    df1 = df1.drop(columns=['包含dict的列名'])
    

3. 更新to_sql的dtype配置

确保所有列都被正确指定类型,若选择存储JSON,可使用SQLAlchemy的JSON类型:

from sqlalchemy.types import JSON, String

df1.to_sql('appeals', con=db, if_exists='append', index=False, dtype={
    # 原有列配置...
    'Location': JSON,  # 若存储为JSON类型
    # 或 'Location': String()  # 若存储为JSON字符串
})

4. 优化数据库连接代码

代码中同时创建了SQLAlchemy连接和psycopg2连接,存在冗余,只需保留SQLAlchemy引擎即可:

# 移除多余的psycopg2连接代码
# conn = psycopg2.connect(conn_string)
# conn.autocommit = True

# 使用SQLAlchemy引擎直接入库
df1.to_sql('appeals', con=db, if_exists='append', index=False, dtype={
    # 你的类型配置
})

conn.close()

内容的提问来源于stack exchange,提问作者Henry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 04:55:13