这是故事。
我有一堆存储过程,它们都有自己的参数类型。
我想要做的是在 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__
,事实证明,它只是为我们在 pcast
和 ccast
之间进行选择。此方法的文档毫无帮助,但进一步查看 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/