使用 psycopg2 将类型转换应用于参数中的数组项
Apply type cast to items of array in parameter with psycopg2
问题
我正在努力将数据插入 table,其中包含 Python 中自定义数据类型的数组列。
方案如下:
CREATE TYPE data_source AS ENUM ('smtp', 'ftp', 'http');
CREATE TABLE IF NOT EXISTS data(
id BIGSERIAL PRIMARY KEY,
foo TEXT NOT NULL,
sources data_source[]
);
然后,我想使用 psycopg2:
从 Python 中插入一些数据到这样的 table 中
foo = "my_text"
sources = ["ftp", "http"]
cursor.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s)
""",
(foo, sources),
)
此代码以运行时异常结束:
LINE 3: ...('my text', ARRAY['ftp...
^
HINT: You will need to rewrite or cast the expression.
我知道我需要对 ARRAY
的每个元素调用 ::data_source
类型转换。我怎样才能做到这一点?
具有 class 和 adapt()
的变体
我试图利用 psycopg2.extensions
包中的 adapt
功能
class Source:
def __init__(self, source):
self.string = source
def adapt_source(source):
quoted = psycopg2.extensions.adapt(source.string).getquoted()
return psycopg2.extensions.AsIs(f"{quoted}::data_source'")
psycopg2.extensions.register_adapter(Source, adapt_source)
foo = "my_text"
sources = [Source("ftp"), Source("http")]
cursor.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s)
""",
(foo, sources),
)
但此代码以:
结尾
psycopg2.errors.SyntaxError: syntax error at or near ""'ftp'""
LINE 3: ...my text', (b"'ftp'"::...
^
我猜问题出在 AsIs
函数中,它结合了 getquoted
函数中的 bytes 并格式化了 string .
任何人都可以帮助我或指出任何解决方案吗?
谢谢
我在评论中提出的完整示例:
CREATE TYPE data_source AS ENUM ('smtp', 'ftp', 'http');
CREATE TABLE IF NOT EXISTS data(
id BIGSERIAL PRIMARY KEY,
foo TEXT NOT NULL,
sources data_source[]
);
import psycopg2
con = psycopg2.connect(database="test", host='localhost', user='postgres')
cur = con.cursor()
foo = "my_text"
source_list = ["ftp", "http"]
sources = '{' + ','.join(source_list) + '}'
sources
'{ftp,http}'
cur.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s)
""",
(foo, sources),
)
con.commit()
select * from data;
id | foo | sources
----+---------+------------
1 | my_text | {ftp,http}
将源列表转换为数组的字符串表示形式,并将其用作 sources
值。
扩展 Adrian Klaver 的答案,您还需要 cast 到您在架构中定义的数据库类型 data_source
。
cur.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s::data_source[])
""",
(foo, sources),
)
con.commit()
这对我有用。
问题
我正在努力将数据插入 table,其中包含 Python 中自定义数据类型的数组列。
方案如下:
CREATE TYPE data_source AS ENUM ('smtp', 'ftp', 'http');
CREATE TABLE IF NOT EXISTS data(
id BIGSERIAL PRIMARY KEY,
foo TEXT NOT NULL,
sources data_source[]
);
然后,我想使用 psycopg2:
从 Python 中插入一些数据到这样的 table 中foo = "my_text"
sources = ["ftp", "http"]
cursor.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s)
""",
(foo, sources),
)
此代码以运行时异常结束:
LINE 3: ...('my text', ARRAY['ftp...
^
HINT: You will need to rewrite or cast the expression.
我知道我需要对 ARRAY
的每个元素调用 ::data_source
类型转换。我怎样才能做到这一点?
具有 class 和 adapt()
的变体我试图利用 psycopg2.extensions
包中的 adapt
功能
class Source:
def __init__(self, source):
self.string = source
def adapt_source(source):
quoted = psycopg2.extensions.adapt(source.string).getquoted()
return psycopg2.extensions.AsIs(f"{quoted}::data_source'")
psycopg2.extensions.register_adapter(Source, adapt_source)
foo = "my_text"
sources = [Source("ftp"), Source("http")]
cursor.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s)
""",
(foo, sources),
)
但此代码以:
结尾psycopg2.errors.SyntaxError: syntax error at or near ""'ftp'""
LINE 3: ...my text', (b"'ftp'"::...
^
我猜问题出在 AsIs
函数中,它结合了 getquoted
函数中的 bytes 并格式化了 string .
任何人都可以帮助我或指出任何解决方案吗?
谢谢
我在评论中提出的完整示例:
CREATE TYPE data_source AS ENUM ('smtp', 'ftp', 'http');
CREATE TABLE IF NOT EXISTS data(
id BIGSERIAL PRIMARY KEY,
foo TEXT NOT NULL,
sources data_source[]
);
import psycopg2
con = psycopg2.connect(database="test", host='localhost', user='postgres')
cur = con.cursor()
foo = "my_text"
source_list = ["ftp", "http"]
sources = '{' + ','.join(source_list) + '}'
sources
'{ftp,http}'
cur.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s)
""",
(foo, sources),
)
con.commit()
select * from data;
id | foo | sources
----+---------+------------
1 | my_text | {ftp,http}
将源列表转换为数组的字符串表示形式,并将其用作 sources
值。
扩展 Adrian Klaver 的答案,您还需要 cast 到您在架构中定义的数据库类型 data_source
。
cur.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s::data_source[])
""",
(foo, sources),
)
con.commit()
这对我有用。