You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SqlAlchemy向PostgreSQL TSRANGE列插入值触发报错

问题根因
  • 首次报错核心是数据库驱动类型不匹配:你当前使用的异步数据库驱动是asyncpg,但代码里导入的DateTimeRange是同步驱动psycopg2专属的范围类型实现,asyncpg无法识别该类实例,它仅支持自身实现的Range对象、元组、列表三类合法范围输入。
  • 第二次使用text()拼接的报错由两个问题共同触发:一是你写的时间范围逻辑错误,结束时间2020年早于开始时间2022年,本身就不符合TSRANGE的取值规则;二是直接将text构造的SQL表达式作为字段值传入参数,会被FastAPI的jsonable_encoder当成普通Python对象尝试序列化,而范围类型本身不支持迭代、也没有__dict__属性,直接触发序列化异常。
解决方案

方案1:使用asyncpg原生Range对象(推荐,类型安全)

直接从asyncpg导入Range类构造时间范围,完全适配异步驱动的序列化逻辑:

from asyncpg import Range
from datetime import datetime

insert_stmt = StaffAvailability.insert()
avail_id = await database.execute(insert_stmt, values={
    "staff_id": kwargs.get("staff_id"),
    "during": Range(
        lower=datetime(2021, 3, 22, 10, 0, 0),
        upper=datetime(2021, 3, 25, 10, 0, 0),
        bounds="[)"  # 边界规则:[代表包含左端点,)代表不包含右端点,和PostgreSQL TSRANGE默认规则一致,可按需调整
    )
})

方案2:传元组自动转换(无需额外导入类型类)

asyncpg支持自动将符合格式的元组转换为PG范围类型,不需要依赖特定Range类:

from datetime import datetime

insert_stmt = StaffAvailability.insert()
avail_id = await database.execute(insert_stmt, values={
    "staff_id": kwargs.get("staff_id"),
    # 元组格式固定为:(下界值, 上界值, 边界字符串),边界参数可省略,省略时默认使用左闭右开规则[)
    "during": (datetime(2021, 3, 22, 10, 0, 0), datetime(2021, 3, 25, 10, 0, 0), "[)")
})

方案3:SQL语句层面直接转换字符串

如果需要直接传字符串格式的范围值,要把类型转换逻辑写在SQL语句构造层,不要把text对象当成普通值传入:

from sqlalchemy import text

insert_stmt = StaffAvailability.insert().values(
    staff_id=kwargs.get("staff_id"),
    # 注意修正时间顺序,上界必须晚于下界
    during=text("CAST('[2022-10-10 10:00, 2022-10-10 12:00)' AS TSRANGE)")
)
avail_id = await database.execute(insert_stmt)

注意:PostgreSQL所有范围类型都要求上界大于等于下界,传入反序的时间会直接触发数据库报错;异步技术栈下不要混用psycopg2和asyncpg的专属数据类型,两个驱动的类型序列化逻辑完全不互通。

内容的提问来源于stack exchange,提问作者Koushik Das

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 04:12:24