1. 为什么我建议你早点把下标取值换掉Python 连 PostgreSQL十有八九用的是 psycopg2。默认情况下cursor.fetchall()返回的是元组列表你只能靠row[0]、row[3]这种下标去拿字段。写的时候爽维护的时候想哭SQL 里加一个字段、调一次顺序所有下标全乱套尤其是select *这种写法字段顺序完全由表结构决定你根本控制不了。这篇就聚焦一件事Python 通过 psycopg2 连接 PostgreSQL 后怎么按列名取数据。核心是cursor_factory这个参数配上RealDictCursor或DictCursor取数就从row[2]变成row[name]SQL 字段顺序变了也不影响你。适合刚接触 psycopg2 的同学也适合手里有一堆下标取值老代码、想平滑替换的人。我会给出可直接复制的连接配置、查询代码、结果校验动作以及几个我实际踩过的坑。你照着跑一遍基本就能把项目里的硬编码下标换掉了。2. 前置准备psycopg2 安装与 TaoToken 接入配置先说环境。psycopg2 有两个常见包名psycopg2和psycopg2-binary。本地开发、写脚本、做验证直接用 binary 版最省事不用折腾编译依赖生产环境如果对二进制分发有顾虑再装源码版。pip install psycopg2-binary如果你后面要接大模型来做 SQL 生成、字段解释、报错分析这类活儿可以顺手把 TaoToken 的接入信息配好。它的 API 地址是https://taotoken.net/api兼容常见的 OpenAI 风格调用方式模型对话、Coding Plan、API Keys 都在控制台里管理。我一般会把 base_url 和 key 放在环境变量里不写死在代码中export TAOTOKEN_API_KEY你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api需要生成或管理 Key 的话走这个入口https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。想先看看模型对话效果用 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。长期写代码、跑 Agent 的话Coding Plan 更划算https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。数据库这边准备一张测试表就够了。下面这段 SQL 你可以直接在 psql 或任意客户端里执行create table if not exists t1( id serial primary key, name text, age int, created_at timestamp default now() ); insert into t1(name, age) select name || g, (g % 60) 18 from generate_series(1, 100) as g;这张表有 4 个字段故意让id和name不相邻就是为了后面演示「下标取值容易错、列名取值不会错」。3. 可复制配置DictCursor 与 RealDictCursor 的写法psycopg2 默认的 cursor 返回 tuple。要按列名取值关键就在创建 cursor 时传cursor_factory。常用的有两种cursor_factory返回类型取值方式特点默认不传tuplerow[0]只能下标顺序敏感DictCursor类字典对象row[name]支持下标也支持列名RealDictCursor真正的 dictrow[name]纯字典序列化友好DictCursor的好处是兼容老代码row[0]和row[name]都能用适合渐进式替换RealDictCursor返回的就是标准 dict直接json.dumps不会报错适合接口返回场景。先看DictCursor的完整可复制版本# coding: utf-8 import psycopg2 import psycopg2.extras conn psycopg2.connect( databasepostgres, userchris, password, hostlocalhost, port5432, ) cursor conn.cursor(cursor_factorypsycopg2.extras.DictCursor) sql select id, name, age, created_at from t1 order by id limit 5 cursor.execute(sql) rows cursor.fetchall() for row in rows: print(row[id], row[name], row[age], row[created_at]) cursor.close() conn.close()再看RealDictCursor区别只在 factory 和返回类型import psycopg2 import psycopg2.extras conn psycopg2.connect( databasepostgres, userchris, password, hostlocalhost, port5432, ) cursor conn.cursor(cursor_factorypsycopg2.extras.RealDictCursor) cursor.execute(select id, name, age from t1 order by id limit 3) rows cursor.fetchall() for row in rows: print(type(row), row[name]) # RealDictCursor 返回的是 dict可以直接序列化 import json print(json.dumps(rows, defaultstr, ensure_asciiFalse))这里有个细节值得说RealDictCursor返回的 dict 里created_at是datetime对象json.dumps默认处理不了所以要加defaultstr。这也是很多人第一次用 RealDictCursor 时遇到的报错来源。连接参数建议不要硬编码。用psycopg2.connect的 keyword 形式或者直接传 DSN 字符串都行import os conn psycopg2.connect( hostos.getenv(PGHOST, localhost), portint(os.getenv(PGPORT, 5432)), dbnameos.getenv(PGDATABASE, postgres), useros.getenv(PGUSER, chris), passwordos.getenv(PGPASSWORD, ), )4. 验证请求与成功结果怎么确认真的按列名取到了写完代码别急着上项目先做三步验证。第一步确认返回类型。DictCursor返回的是DictRow它继承自 list所以isinstance(row, list)是 True但row[name]也能用。RealDictCursor返回的是dict。你可以直接打印类型row rows[0] print(type(row)) # DictCursor: class psycopg2.extras.DictRow # RealDictCursor: class dict print(row.keys()) # 两种都能列出列名第二步故意打乱 SQL 字段顺序看取值是否还正确。这是验证「按列名取值」最直接的方式cursor.execute(select name, id, age from t1 order by id limit 1) row cursor.fetchone() print(row[id], row[name]) # 顺序变了列名取值依然正确如果还是用row[0]这里拿到的就是 name 而不是 id很容易出 bug。第三步校验字段是否存在。列名写错时DictCursor会抛KeyErrorRealDictCursor同样。你可以用in判断或者用.get()兜底if nickname in row: print(row[nickname]) else: print(字段不存在走默认逻辑) # 或者 print(row.get(nickname, 未设置))实测下来RealDictCursor的.get()行为和普通 dict 一致用起来最顺手。跑通后你应该能看到类似输出1 name1 18 2024-05-01 10:00:00 2 name2 19 2024-05-01 10:00:005. 本篇常见错排查报错一TypeError: tuple indices must be integers or slices, not str这是最典型的。原因就是你用了默认 cursor却想用列名取值。解决方式就是创建 cursor 时加cursor_factorypsycopg2.extras.DictCursor或RealDictCursor。注意 factory 是在conn.cursor()时传不是在connect()时传很多人第一次会传错位置。报错二KeyError: name列名拼错或者 SQL 里用了别名但你还按原字段名取。比如select name as user_name from t1这时候要取row[user_name]。另外 PostgreSQL 默认把未加引号的标识符转成小写如果你建表时用了Name这种带引号的大写字段取值时也得写row[Name]大小写敏感。报错三RealDictCursor结果json.dumps失败datetime、Decimal、UUID这些类型不能直接序列化。加defaultstr最省事或者自己写一个 encoder。别去改 cursor问题不在它。报错四连接后查不到数据但表里明明有检查是否忘了conn.commit()。psycopg2 默认开启事务execute后的写操作不 commit 不生效。查询本身不需要 commit但如果你在同一个连接里先插入再查询没 commit 就查不到。另外确认search_path和表所在的 schema 一致。报错五DictCursor和RealDictCursor混用导致类型判断出错有的老代码里判断isinstance(row, dict)用DictCursor时返回的是DictRow不是 dict判断会失败。要么统一用RealDictCursor要么把判断改成hasattr(row, keys)。6. 把列名取值接进你的项目下一步怎么做替换硬编码下标这件事建议分两步走先把新写的查询全部改成RealDictCursor再把老代码里row[0]、row[1]逐个换成列名。换的时候顺手加个字段存在性判断能挡掉不少线上问题。如果你想让大模型帮你批量改写这些取值代码或者根据表结构自动生成带列名的查询可以走模型对话入口https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。需要先拿 Key 的话在这里https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。接入文档和参数说明在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 控制台在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。长期写代码、跑 Agent 任务用 Coding Plan 更稳https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。最后留一个我常用的习惯查询函数统一返回list[dict]内部一律用RealDictCursor出口处做一次类型转换。这样上层业务永远拿到的是标准字典序列化、断言、mock 都省心。
企业数字化 ERP 产品动态
相关推荐
Modbus TCP温湿度变送器选型实战指南 1. 为什么机房动环监控的第一道关卡,往往卡在“温湿度变送器”上?我接手过二十多个中小型IDC机房的动环系统改造项目,几乎每一家都踩过同一个坑:前期预算全砸在服务器、UPS、精密空调和视频监控上,等真正部署动环平台时… · 2026/9/26 11:18:01
Go SDK实战:用Go语言开发高性能MCP Server并接入TaoToken统一API通道 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 11:18:01
超低门槛!新手友好版OpenClaw部署教程:TaoToken统一Key接入与config.toml配置骨架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 11:17:55
牛津词典结构化:从PDF到Excel与SQL的完整转换指南 简介:《牛津英语词典》非PDF版数据资源,以Excel和SQL双格式呈现,面向需要批量查词、二次开发或自建翻译工具的英语学习者与开发者。包体共2个文件,含Excel表格与SQL脚本,压缩后仅2.63MB,便于下载与归档。Ex… · 2026/9/26 11:57:45
Sublime Text 3绿色便携版实战:解压即用、配置迁移与避坑指南 简介:Sublime Text 3免安装版压缩包,专为需要快速搭建编码环境的开发者准备,省去安装流程,解压即可使用,适合日常脚本编写、前端调试、多语言编辑等场景。压缩包共1827个文件,约23.27MB,包含914… · 2026/9/26 11:57:45
导师推荐的8个AI论文工具全流程实操手册 开学第三周,导师把我叫到办公室,屏幕上摊开七八个AI工具页面,跟我说:“你别再手动一条条翻文献了,这些工具用起来。”说实话,当时我第一反应是“用AI写论文算不算学术不端”,但导师补了一句&… · 2026/9/26 11:57:45
用Docker Compose部署OnlyOffice:架构、配置与避坑实践指南 在公司内网搭一套能在线打开、编辑、协同处理 Word、Excel、PPT 的文档服务,OnlyOffice 几乎是最绕不开的选择;只要你的机器上装了 Docker,用 Docker Compose 部署 OnlyOffice 又是目前公认最省心的一条路。官方镜像把 Nginx、Node.js、Postg… · 2026/9/26 11:57:45
Socket实战排查:从状态机、半包粘包到WebSocket与嵌入式lwIP 先声明一下:Socket 这个东西,入门教程满大街都是,但热搜词列表里那些真实问题——error 2002 (HY000)、bind: only one usage of each socket address、no more data to read from socket、listen tcp 127.0.0.1:11434: bind、甚至是FreeRTOS… · 2026/9/26 11:57:45
Atlas 300V 24G推理加速卡部署YOLO全流程 做AI推理部署这些年,群里问得最多的两个问题,一个是“atlas能跑YOLO吗”,另一个是“atlas 300v 24g到底是不是运算加速卡”。这两个问题看起来基础,但背后牵扯出一整套从硬件选型到软件栈的取舍逻辑。我先给个明确结论:… · 2026/9/26 11:57:37
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46