我在 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,所以我知道什么。
我的直觉还认为我缺少一些映射特殊酱料,但同样......我知道什么?
一个简单的工作示例来验证它是否可以工作:
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), '[)'))