使用 SQLAlchemy 插入计算值会给出 ProgrammingError

Inserting a calculated value with SQLAlchemy gives ProgrammingError

我有一个 table search,其列 vector 类型为 tsvector。我想使用 SQLAlchemy 核心 API 来插入行。计算 vector 需要 1) 在 Python 中进行一些处理和 2) 调用 to_tsvector(一个 PG 函数)。

我正在弄乱 conn.execute(insert(Search), [{'vector': func.to_tsvector('here is a string')}]) 但我得到了

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'Function'

我正在尝试复制 SQL 查询 insert into search(vector) values (to_tsvector('here is a string'))

这对我来说很奇怪,我认为这是一个错误,但它不是错误。 zzzeek 在此讨论中对此进行了解释:

https://github.com/sqlalchemy/sqlalchemy/discussions/7640

您需要使用 insert().values() 喜欢 session.execute(tbl.insert().values(values)) 而不是直接使用 session.execute(tbl.insert(), values).

万一它丢失了,你可以像这个例子一样执行插入:

代码

from sqlalchemy import (
    create_engine,
    Integer,
    Text,
    DateTime,
)
from sqlalchemy.schema import (
    Column,
    MetaData,
)
from sqlalchemy.sql import func, not_
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import Session
from sqlalchemy.dialects.postgresql import TSVECTOR
from sqlalchemy.exc import ProgrammingError


metadata = MetaData()

Base = declarative_base(metadata=metadata)

engine = create_engine('postgresql+psycopg2://username:password@/database', echo=False)


class Doc(Base):
    __tablename__ = "docs"
    id = Column(Integer, primary_key=True, index=True)
    text = Column(Text, nullable=True)
    vector = Column(TSVECTOR, nullable=True)
    created_on = Column(DateTime, nullable=False)


metadata.create_all(engine)


doc_specs = [{
    "text": "Frog jumping.",
}, {
    "text": "Fish swimming.",
}, {
    "text": "Bird flying.",
}, {
    "text": "Cat jumping and flying.",
}]


with Session(engine) as session:
    values = [{
        "created_on": func.now(),
        "text": spec["text"],
        "vector": func.to_tsvector(spec["text"])
    } for spec in doc_specs]
    session.execute(Doc.__table__.insert().values(values))
    session.commit()

    print ("Matches")
    for doc in session.query(Doc).filter(Doc.vector.match("jumping & flying")):
        print (doc.id, doc.text, doc.vector)
    print ("Misses")
    for doc in session.query(Doc).filter(~Doc.vector.match("jumping & flying")):
        print (doc.id, doc.text, doc.vector)

输出

DROP DATABASE
CREATE DATABASE
Matches
4 Cat jumping and flying. 'cat':1 'fli':4 'jump':2
Misses
1 Frog jumping. 'frog':1 'jump':2
2 Fish swimming. 'fish':1 'swim':2
3 Bird flying. 'bird':1 'fli':2