python - 将 psql 类型 oid 映射到 python 类型 - 使用 psycopg2

标签 python postgresql psycopg2

这是故事。

我有一堆存储过程,它们都有自己的参数类型。
我想要做的是在 python 中创建一些类型安全层,这样我就可以在访问数据库之前确保所有值都是正确的类型。

当然我不想用 python 再次编写整个模式,所以我想我可以通过从数据库中获取参数名称和类型来在启动时自动生成此信息。

所以我继续破解这个查询只是为了测试

SELECT proname, proargnames, proargtypes 
FROM pg_catalog.pg_namespace n
JOIN pg_catalog.pg_proc p
ON pronamespace = n.oid
WHERE nspname = 'public';

然后我从 python 运行它,对于'proargtypes',我为每个结果得到一个这样的字符串

'1043 23 1043'

我敏锐的眼睛告诉我这些是 postgresql 类型的 oid,由空格分隔,这个特定的字符串意味着函数接受 varchar、integer、varchar。 所以在 python 中,这应该是

(unicode, int, unicode)

现在如何从这些数字中获取 python 类型?

理想的最终结果应该是这样的

In [129]: get_python_type(23)
Out[129]: int

我查看了所有 psycopg2,我发现最接近的是“extensions.string_types”,但它只是将 oid 映射到 sql 类型名称。

最佳答案

如果您需要 Python 类型类,就像您可能从 SQLALchemy 列对象中获得的那样,您需要构建和维护您自己的映射。 psycopg2 没有,甚至在内部也没有。

但是如果您想要的是一种从oid 到将原始值转换为Python 实例的函数的方法,psycopg2.extensions.string_types 实际上已经你需要什么。它可能看起来只是从 oid 到名称的映射,但事实并非如此:它的值不是字符串,它们是 psycopg2._psycopg.type 的实例>。是时候深入研究一些代码了。

psycopg2 公开了一个用于注册新类型转换器的 API,我们可以使用它来追溯到涉及类型转换的 C 代码;这以 typecastObject 为中心 typecast.c ,毫不奇怪,它映射到我们在老 friend string_types 中找到的 psycopg2._psycopg.type。这个对象包含指向两个函数的指针,pcast(用于 Python 转换函数)和 ccast(用于 C 转换函数),这看起来就像我们想要的——随便选择一个存在并调用它,问题解决了。除了它们不在公开的属性中(name,它只是一个标签,values,它是一个 oid 列表)。该类型向 Python 公开的是 __call__,事实证明,它只是为我们在 pcastccast 之间进行选择。此方法的文档毫无帮助,但进一步查看 C 代码 shows它有两个参数:一个包含原始值的字符串和一个游标对象。

>>> import psycopg2.extensions
>>> cur = something_that_gets_a_cursor_object()
>>> psycopg2.extensions.string_types[23]
<psycopg2._psycopg.type 'INTEGER' at 0xDEADBEEF>
>>> psycopg2.extensions.string_types[23]('100', cur)
100
>>> psycopg2.extensions.string_types[23]('10.0', cur)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '10.0'
>>> string_types[1114]
<psycopg2._psycopg.type 'DATETIME' at 0xDEADBEEF>
>>> string_types[1114]('2018-11-15 21:35:21', cur)
datetime.datetime(2018, 11, 15, 21, 35, 21)

不幸的是需要游标,事实上,并不总是需要游标:

>>> string_types[23]('100', None)
100

但是任何与转换实际字符串(例如 varchar)类型相关的事情都取决于 PostgreSQL 服务器的语言环境,至少在 Python 3 编译中是这样,并且传递 None 对于那些施法者来说,不仅仅是失败——它是段错误。您提到的方法 cursor.cast(oid, raw) 本质上是 psycopg2.extensions.string_types 中脚轮的包装器,在某些情况下可能更方便。

我能想到的需要游标和连接的唯一解决方法是本质上构建一个模拟连接对象。如果它在不连接到实际数据库的情况下公开所有相关环境信息,则它可以附加到游标对象并与 string_types[oid](raw, cur)cur 一起使用。 cast(oid, raw),但模拟将用 C 语言构建,留给读者作为练习。

关于python - 将 psql 类型 oid 映射到 python 类型 - 使用 psycopg2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11254769/

相关文章:

Python GTK3 : how to create a Gtk. 文件选择对话框?

python - 您如何形成数据以在 scikit 学习决策树中制作一个包含 n 个特征和 n 个样本的数组?

python-3.x - Psycopg2 - 在字符串格式化期间并非所有参数都转换

python - many2one 字段不显示字段值

c++ - 从在 postgresql 上运行的 C++ 文件打印

django - 主键值未正确递增

sql - Postgresql:从数字开始提取文本

python - psycopg2 - 如何始终将非字符串值转换为字符串

django - 保存 geodjango PointField 时出错

python - Youtube API 请求凭据