“没有函数与给定名称和参数类型匹配。”当尝试使用 Sqlalchemy ORM 插入 `DateTimeTzRange` 时

问题描述 投票:0回答:1

我在 Postgres 15 数据库中有一个数据库表,它有两列(除其他外),一列的类型为

daterange
,另一列的类型为
tstzrange

我们有一些代码,通过将

sqlalchemy.dialects.postgresql.Range
转换为
psycopg2.extras.DateRange
psycopg2.extras.DateTimeTzRange
,使用原始 SQL(通过 sqlalchemy 核心)插入到该表中。这很好用。

我正在尝试连接 Sqlalchemy ORM,但当我在会话中调用

commit()
时,出现以下错误:

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedFunction)
function daterange(timestamp with time zone, unknown, unknown) does not exist
LINE 1: ...y.co.uk', '81740d75-d75a-4187-8b13-e28ac2e4dbf8', daterange(...
                                                              ^
HINT:  No function matches the given name and argument types. 
You might need to add explicit type casts.

[SQL: INSERT INTO "user" (user_id, username, full_name, provider_subject_id, effective, asserted) 
SELECT p0::VARCHAR, p1::VARCHAR, p2::VARCHAR, p3::VARCHAR,
p4::DATERANGE, p5::TSTZRANGE FROM (VALUES (%(user_id__0)s,
%(username__0)s, %(full_name__0)s, 
%(pro ... 233 characters truncated ... en(p0, p1, p2, p3, p4, p5, sen_counter) 
ORDER BY sen_counter RETURNING "user".id, "user".id AS id__1]

[parameters: {'effective__0': DateRange(datetime.datetime(2024, 4, 30, 13, 43, 31, 985502, tzinfo=<UTC>), None, '[)'),
'provider_subject_id__0': '81740d75-d75a-4187-8b13-e28ac2e4dbf8',
'full_name__0': '[email protected]', 
'user_id__0': '81740d75-d75a-4187-8b13-e28ac2e4dbf8', 
'asserted__0': DateTimeTZRange(datetime.datetime(2024, 4, 30, 13, 43, 31, 985513, tzinfo=<UTC>), None, '[)'), 
'username__0': '[email protected]', 
'effective__1': DateRange(datetime.datetime(2024, 4, 30, 13, 43, 31, 985502, tzinfo=<UTC>), None, '[)'), 
'provider_subject_id__1': '81740d75-d75a-4187-8b13-e28ac2e4dbf8',
'full_name__1': '[email protected]', 
'user_id__1': '81740d75-d75a-4187-8b13-e28ac2e4dbf8', 
'asserted__1': DateTimeTZRange(datetime.datetime(2024, 4, 30, 13, 43, 31, 985513, tzinfo=<UTC>), None, '[)'), 
'username__1': '[email protected]'}]
(Background on this error at: https://sqlalche.me/e/20/f405)

我的

UserModel
看起来像:

class ModelBase(DeclarativeBase):
    pass

class UserModel(ModelBase):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[str] = mapped_column(String)
    username: Mapped[str] = mapped_column(String)
    full_name: Mapped[str] = mapped_column(String)
    provider_subject_id: Mapped[str] = mapped_column(String)
    effective: Mapped[DATERANGE] = Column(DATERANGE)
    asserted: Mapped[TSTZRANGE] = Column(TSTZRANGE)

用户表定义如下:

from sqlalchemy import MetaData


metadata_obj = MetaData()

Table("user", metadata_obj, 
        Column("id", PRIMARY_KEY_TYPE, primary_key=True),
        Column("user_id", data_types.CODE_TYPE, nullable=False),
        Column("role", data_types.CODE_TYPE, nullable=True),
        Column("username", data_types.CODE_TYPE, nullable=False),
        Column("full_name", data_types.SHORT_FIXED_STRING_TYPE, nullable=False),
        Column("provider_subject_id", data_types.CODE_TYPE, nullable=True),            
        Column("effective", DATERANGE, nullable=False),
        Column("asserted", TSTZRANGE, nullable=False)
)

当我尝试提交会话时,出现上述错误,如下所示:

session = session_factory()

user = UserModel(
   # ...
   asserted = DateTimeTZRange(asserted_value.lower, asserted_value.upper, bounds=asserted_value.bounds)
   effective = DateRange(effective_value.lower, effective_value.upper, bounds=effective_value.bounds)
   )

session.add(user)
session.commit() #💥

所以我的直觉说这应该可以工作,因为它使用原始 SQL,而且我是 python/sqlalchemy/postgres n00b,所以我知道什么。

我的直觉还认为我缺少一些映射特殊酱料,但同样......我知道什么?

python python-3.x postgresql sqlalchemy psycopg2
1个回答
0
投票

一个简单的工作示例来验证它是否可以工作:

import psycopg2
from psycopg2.extras import DateRange
con = psycopg2.connect("dbname=test user=postgres port=5452")
cur = con.cursor()
cur.execute("create table dr_test(id integer, dr_field daterange)")
con.commit()
cur.execute("insert into dr_test values(%(id)s, %(dr)s)", {"id": 1, "dr": DateRange('2024-04-01', '2024-04-30', '[)')})
con.commit()
cur.execute("select * from dr_test")
cur.fetchone()
(1, DateRange(datetime.date(2024, 4, 1), datetime.date(2024, 4, 30), '[)'))
© www.soinside.com 2019 - 2024. All rights reserved.