这是故事。
我有一堆存储过程,并且都有自己的参数类型 我想要做的是在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类型名称。
答案 0 :(得分:1)
postgres类型和python类型的映射给出了here。这有帮助吗?
编辑: 当您从表中读取记录时,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类型的迂回方式。我只想引用这两个数据库之间的众多类型映射之一,如this
答案 1 :(得分:1)
如果要使用Python类型类(例如,可以从SQLALchemy
列对象中获取),则需要构建和维护自己的映射。 psycopg2
甚至在内部都没有。
但是,如果您想要的是从oid
到将原始值转换为Python实例的函数的方法,则psycopg2.extensions.string_types
实际上已经是您所需要的。看起来好像只是从oid
到名称的映射,但这不是真的:它的值不是字符串,而是psycopg2._psycopg.type
的实例。是时候研究一些代码了。
psycopg2
提供了用于注册新类型转换器的API,我们可以使用该API追溯到与类型转换有关的C代码;围绕typecastObject
中的
typecast.c,毫不奇怪,它映射到我们在老朋友psycopg2._psycopg.type
中找到的string_types
。该对象包含指向两个函数的指针,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
类型)所必需的工作至少取决于Python 3编译中的PostgreSQL服务器的语言环境,并且将None
传递给那些脚轮并不会”只是失败-它存在段错误。您提到的方法cursor.cast(oid, raw)
实际上是psycopg2.extensions.string_types
中脚轮的包装,在某些情况下可能更方便。
我能想到的唯一需要游标和连接的解决方法是建立一个模拟连接对象。如果它在不连接到实际数据库的情况下公开了所有相关的环境信息,则可以将其附加到游标对象上,并与string_types[oid](raw, cur)
或cur.cast(oid, raw)
一起使用,但是该模拟将在C和留给读者练习。