#python #postgresql #psycopg2
Вопрос:
Вопрос
Я борюсь с вставкой данных в таблицу со столбцом массива пользовательского типа данных в 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[]
);
затем я хочу вставить некоторые данные в такую таблицу из Python с помощью psycopg2:
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.
Я понимаю, что мне нужно вызвать ::data_source
приведение типов для каждого элемента ARRAY
. Как я могу этого достичь?
Вариант с классом и адаптацией()
Я попытался воспользоваться преимуществами adapt
функции из psycopg2.extensions
пакета
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
функции и отформатированную строку.
Может ли кто-нибудь помочь мне или указать мне на какое-либо решение?
Спасибо
Комментарии:
1. Перейти
sources = ["ftp", "http"]
к источникам ='{"ftp", "http"}'
.
Ответ №1:
Расширяя ответ Адриана Клавера, вам также необходимо привести к типу базы data_source
данных, определенному в схеме.
cur.execute(
"""
INSERT INTO data(foo, sources)
VALUES (%s, %s::data_source[])
""",
(foo, sources),
)
con.commit()
Это работает на меня.
Ответ №2:
Полный пример того, что я предложил в своем комментарии:
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
значения.
Комментарии:
1. Приятно и спасибо. Это тоже работает
2. Это работает до тех пор, пока в значениях нет символов для экранирования, таких как запятая или скобка.