繁体   English   中英

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

[英]mapping psql type oids to python types - with 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',但这只是将oids映射到sql类型名称。

这里给出了postgres类型和python类型的映射。 这有帮助吗?

编辑:当您从表中读取记录时,postgres(或任何数据库)驱动程序将自动将记录列类型映射到Python类型。

cur = con.cursor()
cur.execute("SELECT * FROM Writers")

row = cur.fetchone()

for index, val in enumerate(row):
    print "column {0} value {1} of type {2}".format(index, val, type(val))

现在,您只需在编写MySQL接口代码时将Python类型映射到MySQL类型。 但是,坦率地说,这是将类型从PostgreSQL类型映射到MySQL类型的迂回方式。 我会像这样引用这两个数据库之间的众多类型映射之一

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

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

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

>>> 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语言构建,并留给读者练习。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM